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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/**
* Tests some practical use cases of the $facet stage.
*/
(function() {
"use strict";
load("jstests/noPassthrough/libs/server_parameter_helpers.js"); // For setParameterOnAllHosts.
load("jstests/libs/discover_topology.js"); // For findDataBearingNodes.
const dbName = "test";
const collName = jsTest.name();
Random.setRandomSeed();
/**
* Helper to get a random entry out of an array.
*/
function randomChoice(array) {
return array[Random.randInt(array.length)];
}
/**
* Helper to generate a randomized document with the following schema:
* {
* manufacturer: <string>,
* price: <double>,
* screenSize: <double>
* }
*/
function generateRandomDocument(docId) {
const manufacturers =
["Sony", "Samsung", "LG", "Panasonic", "Mitsubishi", "Vizio", "Toshiba", "Sharp"];
const minPrice = 100;
const maxPrice = 4000;
const minScreenSize = 18;
const maxScreenSize = 40;
return {
_id: docId,
manufacturer: randomChoice(manufacturers),
price: Random.randInt(maxPrice - minPrice + 1) + minPrice,
screenSize: Random.randInt(maxScreenSize - minScreenSize + 1) + minScreenSize,
};
}
/**
* Inserts 'nDocs' documents into collection given by 'dbName' and 'collName'. Documents will
* have _ids in the range [0, nDocs).
*/
function populateData(nDocs) {
var coll = db.getCollection(collName);
coll.remove({}); // Don't drop the collection, since it might be sharded.
var bulk = coll.initializeUnorderedBulkOp();
for (var i = 0; i < nDocs; i++) {
const doc = generateRandomDocument(i);
bulk.insert(doc);
}
assert.commandWorked(bulk.execute());
}
const nDocs = 1000 * 10;
populateData(nDocs);
const coll = db.getCollection(collName);
//
// Compute the most common manufacturers, and the number of TVs in each price range.
//
// First compute each separately, to make sure we have the correct results.
const manufacturerPipe = [
{$sortByCount: "$manufacturer"},
// Sort by count and then by _id in case there are two manufacturers with an equal
// count.
{$sort: {count: -1, _id: 1}},
];
const bucketedPricePipe = [
{
$bucket: {groupBy: "$price", boundaries: [0, 500, 1000, 1500, 2000], default: 2000},
},
{$sort: {count: -1}}
];
const automaticallyBucketedPricePipe = [{$bucketAuto: {groupBy: "$price", buckets: 5}}];
const mostCommonManufacturers = coll.aggregate(manufacturerPipe).toArray();
const numTVsBucketedByPriceRange = coll.aggregate(bucketedPricePipe).toArray();
const numTVsAutomaticallyBucketedByPriceRange =
coll.aggregate(automaticallyBucketedPricePipe).toArray();
const facetPipe = [{
$facet: {
manufacturers: manufacturerPipe,
bucketedPrices: bucketedPricePipe,
autoBucketedPrices: automaticallyBucketedPricePipe
}
}];
// Then compute the results using $facet.
const facetResult = coll.aggregate(facetPipe).toArray();
assert.eq(facetResult.length, 1);
const facetManufacturers = facetResult[0].manufacturers;
const facetBucketedPrices = facetResult[0].bucketedPrices;
const facetAutoBucketedPrices = facetResult[0].autoBucketedPrices;
// Then assert they are the same.
assert.sameMembers(facetManufacturers, mostCommonManufacturers);
assert.sameMembers(facetBucketedPrices, numTVsBucketedByPriceRange);
assert.sameMembers(facetAutoBucketedPrices, numTVsAutomaticallyBucketedByPriceRange);
/**
* A simple case using $facet + $match. This also tests the bug found in SERVER-50504 is fixed.
*/
coll.drop();
assert.commandWorked(coll.insert({"_id": 1, "quizzes": [{"score": 100}]}));
assert.commandWorked(coll.insert({"_id": 2, "quizzes": [{"score": 200}]}));
const facetPipeline =
[{$facet: {scoreRank: [{$match: {'quizzes.0.score': {$gt: 0}}}, {$count: 'count'}]}}];
const facetRes = coll.aggregate(facetPipeline).toArray();
assert.eq(facetRes.length, 1);
const scoreRank = facetRes[0]['scoreRank'];
assert.eq(scoreRank.length, 1);
assert.eq(scoreRank[0]['count'], 2);
}());
|