summaryrefslogtreecommitdiff
path: root/jstests/sharding/query/mrShardedOutput.js
blob: 05abd73679376221d4ad285468481800e46bb34c (plain)
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();
}());