1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
// Tests the behavior of mapReduce outputting to a sharded collection and specifying the 'sharded'
// flag.
// This test stresses behavior that is only true of the mapReduce implementation using aggregation,
// so it cannot be run in mixed-version suites.
(function() {
"use strict";
load("jstests/libs/fixture_helpers.js"); // For 'FixtureHelpers'.
const st = new ShardingTest({shards: 2, other: {chunkSize: 1}});
const config = st.getDB("config");
const testDB = st.getDB("test");
const inputColl = testDB.foo;
const outputColl = testDB.mr_sharded_out;
const numDocs = 500;
const str = new Array(1024).join('a');
// Shard the input collection by "a" and split into two chunks, one on each shard.
st.shardColl(inputColl, {a: 1}, {a: numDocs / 2}, {a: numDocs});
function map() {
emit(this._id, {count: 1, y: this.y});
}
function reduce(key, values) {
// 'values' can contain a null entry if we're using reduce for output mode "reduce" and the
// target doesn't exist.
return {
count: Array.sum(values.map(val => val === null ? 0 : val.count)),
y: values.map(val => val === null ? "" : val.y).join("")
};
}
const bulk = inputColl.initializeUnorderedBulkOp();
for (let i = 0; i < numDocs; ++i) {
bulk.insert({_id: i, a: numDocs + i, y: str, i: numDocs + i});
}
assert.commandWorked(bulk.execute());
// Should not be able to replace to a sharded collection.
assert.throwsWithCode(
() => inputColl.mapReduce(map, reduce, {out: {replace: outputColl.getName(), sharded: true}}),
ErrorCodes.InvalidOptions);
// Should fail if we specify "merge" or "reduce" with sharded: true and the collection does not yet
// exist as sharded.
assert.throwsWithCode(
() => inputColl.mapReduce(map, reduce, {out: {merge: outputColl.getName(), sharded: true}}),
ErrorCodes.InvalidOptions);
assert.throwsWithCode(
() => inputColl.mapReduce(map, reduce, {out: {reduce: outputColl.getName(), sharded: true}}),
ErrorCodes.InvalidOptions);
// Now create and shard the output collection, again with one chunk on each shard.
st.shardColl(outputColl, {_id: 1}, {_id: numDocs / 2}, {_id: numDocs / 2});
// Should be able to output successfully with any non-replace mode now.
inputColl.mapReduce(map, reduce, {out: {merge: outputColl.getName(), sharded: true}});
assert.eq(numDocs, outputColl.find().itcount());
// It should not be required to specify the sharded option anymore.
inputColl.mapReduce(map, reduce, {out: {merge: outputColl.getName()}});
assert.eq(numDocs, outputColl.find().itcount());
assert(FixtureHelpers.isSharded(outputColl));
// Now remove half of the output collection to prove that we can "reduce" with those that exist.
assert.commandWorked(outputColl.remove({_id: {$mod: [2, 0]}}));
inputColl.mapReduce(map, reduce, {out: {reduce: outputColl.getName(), sharded: true}});
assert.eq(numDocs, outputColl.find().itcount());
const evenResult = outputColl.findOne({_id: {$mod: [2, 0]}});
const oddResult = outputColl.findOne({_id: {$mod: [2, 1]}});
assert.eq(evenResult.value.count * 2, oddResult.value.count, [evenResult, oddResult]);
// Should not be able to use replace mode if the collection exists and is sharded, even if the
// 'sharded' option is not specified.
assert.throwsWithCode(
() => inputColl.mapReduce(map, reduce, {out: {replace: outputColl.getName()}}),
ErrorCodes.IllegalOperation);
st.stop();
}());
|