summaryrefslogtreecommitdiff
path: root/jstests/aggregation/sources/facet/use_cases.js
blob: 1a2d662d4374990b5f36c44bb11caa2a636998f6 (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
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);
}());