Files
mongo/jstests/core/mr_correctness.js

185 lines
5.8 KiB
JavaScript

// Basic correctness tests for the mapReduce command.
// @tags: [
// # mapReduce does not support afterClusterTime.
// does_not_support_causal_consistency,
// does_not_support_stepdowns,
// requires_fastcount,
// requires_getmore,
// uses_map_reduce_with_temp_collections,
// ]
(function() {
"use strict";
load("jstests/libs/fixture_helpers.js"); // For "FixtureHelpers".
const coll = db.mr_correctness;
coll.drop();
assert.commandWorked(coll.insert({x: 1, tags: ["a", "b"]}));
assert.commandWorked(coll.insert({x: 2, tags: ["b", "c"]}));
assert.commandWorked(coll.insert({x: 3, tags: ["c", "a"]}));
assert.commandWorked(coll.insert({x: 4, tags: ["b", "c"]}));
function mapToObj() {
this.tags.forEach(function(z) {
emit(z, {count: 1});
});
}
function reduceObjs(key, values) {
let total = 0;
for (let i = 0; i < values.length; i++) {
total += values[i].count;
}
return {count: total};
}
const outColl = db[coll.getName() + "_out"];
outColl.drop();
(function testBasicMapReduce() {
const res = db.runCommand({
mapReduce: coll.getName(),
map: mapToObj,
reduce: reduceObjs,
out: {merge: outColl.getName()}
});
assert.commandWorked(res);
assert.eq(res.result, outColl.getName());
assert.eq(
3,
outColl.find().count(),
() =>
`expected 3 distinct tags: ['a', 'b', 'c'], found ${tojson(outColl.find().toArray())}`);
const keys = {};
for (let result of outColl.find().toArray()) {
keys[result._id] = result.value.count;
}
assert.eq(3, Object.keySet(keys).length, Object.keySet(keys));
assert.eq(2, keys.a, () => `Expected 2 occurences of the tag 'a': ${tojson(keys)}`);
assert.eq(3, keys.b, () => `Expected 3 occurences of the tag 'b': ${tojson(keys)}`);
assert.eq(3, keys.c, () => `Expected 3 occurences of the tag 'c': ${tojson(keys)}`);
outColl.drop();
})();
(function testMapReduceWithPredicate() {
const res = db.runCommand({
mapReduce: coll.getName(),
map: mapToObj,
reduce: reduceObjs,
query: {x: {$gt: 2}},
out: {merge: outColl.getName()}
});
assert.commandWorked(res);
assert.eq(res.result, outColl.getName());
const keys = {};
for (let result of outColl.find().toArray()) {
keys[result._id] = result.value.count;
}
assert.eq(3, Object.keySet(keys).length, Object.keySet(keys));
assert.eq(1, keys.a, () => `Expected 1 occurence of the tag 'a': ${tojson(keys)}`);
assert.eq(1, keys.b, () => `Expected 1 occurence of the tag 'b': ${tojson(keys)}`);
assert.eq(2, keys.c, () => `Expected 2 occurences of the tag 'c': ${tojson(keys)}`);
outColl.drop();
}());
function mapToNumber() {
for (let tag of this.tags) {
emit(tag, 1);
}
}
function reduceNumbers(key, values) {
let total = 0;
for (let val of values) {
total += val;
}
return total;
}
// Now do a similar test but using the above map and reduce functions which use numbers as the value
// instead of objects.
(function testBasicMapReduceWithNumberValues() {
const res = db.runCommand({
mapReduce: coll.getName(),
map: mapToNumber,
reduce: reduceNumbers,
query: {x: {$gt: 2}},
out: {merge: outColl.getName()}
});
assert.commandWorked(res);
assert.eq(res.result, outColl.getName());
const keys = {};
for (let result of outColl.find().toArray()) {
keys[result._id] = result.value;
}
assert.eq(3, Object.keySet(keys).length, Object.keySet(keys));
assert.eq(1, keys.a, () => `Expected 1 occurence of the tag 'a': ${tojson(keys)}`);
assert.eq(1, keys.b, () => `Expected 1 occurence of the tag 'b': ${tojson(keys)}`);
assert.eq(2, keys.c, () => `Expected 2 occurences of the tag 'c': ${tojson(keys)}`);
outColl.drop();
}());
(function testMapReduceWithManyValuesGrouped() {
const bulk = coll.initializeUnorderedBulkOp();
for (let i = 5; i < 1000; i++) {
bulk.insert({x: i, tags: ["b", "d"]});
}
assert.commandWorked(bulk.execute());
const res = db.runCommand({
mapReduce: coll.getName(),
map: mapToObj,
reduce: reduceObjs,
out: {merge: outColl.getName()}
});
assert.commandWorked(res);
assert.eq(res.result, outColl.getName());
assert.eq(4,
outColl.find().count(),
() => `expected 4 distinct tags: ['a', 'b', 'c', 'd'], found ${
tojson(outColl.find().toArray())}`);
assert.eq("a,b,c,d", outColl.distinct("_id"));
assert.eq(2, outColl.findOne({_id: "a"}).value.count, () => outColl.findOne({_id: "a"}));
assert.eq(998, outColl.findOne({_id: "b"}).value.count, () => outColl.findOne({_id: "b"}));
assert.eq(3, outColl.findOne({_id: "c"}).value.count, () => outColl.findOne({_id: "c"}));
assert.eq(995, outColl.findOne({_id: "d"}).value.count, () => outColl.findOne({_id: "d"}));
outColl.drop();
}());
(function testHighCardinalityKeySet() {
let correctValues = {};
coll.drop();
const bulk = coll.initializeUnorderedBulkOp();
for (let i = 0; i < 20000; i++) {
const tag = "Z" + i % 10000;
if (!correctValues[tag])
correctValues[tag] = 1;
else
correctValues[tag]++;
bulk.insert({x: i, tags: [tag]});
}
assert.commandWorked(bulk.execute());
const res = db.runCommand({
mapReduce: coll.getName(),
out: {merge: outColl.getName()},
map: mapToObj,
reduce: reduceObjs
});
assert.commandWorked(res);
assert.eq(res.result, outColl.getName());
let actualValues = {};
outColl.find().forEach(function(resultDoc) {
actualValues[resultDoc._id] = resultDoc.value.count;
});
for (let key in actualValues) {
assert.eq(correctValues[key], actualValues[key], key);
}
}());
coll.drop();
outColl.drop();
}());