summaryrefslogtreecommitdiff
path: root/jstests/core/views/views_find.js
blob: 18e084b81865f6dc29954b135f120d70312f0a7e (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
/**
 * Tests the find command on views.
 * @tags: [requires_find_command, requires_getmore]
 */
(function() {
    "use strict";

    // For arrayEq and orderedArrayEq.
    load("jstests/aggregation/extras/utils.js");

    let viewsDB = db.getSiblingDB("views_find");
    assert.commandWorked(viewsDB.dropDatabase());

    // Helper functions.
    let assertFindResultEq = function(cmd, expected, ordered) {
        let res = viewsDB.runCommand(cmd);
        assert.commandWorked(res);
        let arr = new DBCommandCursor(viewsDB, res, 5).toArray();
        let errmsg = tojson({expected: expected, got: arr});

        if (typeof(ordered) === "undefined" || !ordered)
            assert(arrayEq(arr, expected), errmsg);
        else
            assert(orderedArrayEq(arr, expected), errmsg);
    };

    // Populate a collection with some test data.
    let allDocuments = [];
    allDocuments.push({_id: "New York", state: "NY", pop: 7});
    allDocuments.push({_id: "Newark", state: "NJ", pop: 3});
    allDocuments.push({_id: "Palo Alto", state: "CA", pop: 10});
    allDocuments.push({_id: "San Francisco", state: "CA", pop: 4});
    allDocuments.push({_id: "Trenton", state: "NJ", pop: 5});

    let coll = viewsDB.coll;
    let bulk = coll.initializeUnorderedBulkOp();
    allDocuments.forEach(function(doc) {
        bulk.insert(doc);
    });
    assert.writeOK(bulk.execute());

    // Create views on the data.
    assert.commandWorked(
        viewsDB.runCommand({create: "identityView", viewOn: "coll", pipeline: [{$match: {}}]}));
    assert.commandWorked(viewsDB.runCommand({
        create: "noIdView",
        viewOn: "coll",
        pipeline: [{$match: {}}, {$project: {_id: 0, state: 1, pop: 1}}]
    }));

    // Filters and "simple" projections.
    assertFindResultEq({find: "identityView"}, allDocuments);
    assertFindResultEq({find: "identityView", filter: {state: "NJ"}, projection: {_id: 1}},
                       [{_id: "Trenton"}, {_id: "Newark"}]);

    // A view that projects out the _id should still work with the find command.
    assertFindResultEq({find: "noIdView", filter: {state: "NY"}, projection: {pop: 1}}, [{pop: 7}]);

    // Sort, limit and batchSize.
    const doOrderedSort = true;
    assertFindResultEq({find: "identityView", sort: {_id: 1}}, allDocuments, doOrderedSort);
    assertFindResultEq(
        {find: "identityView", limit: 1, batchSize: 1, sort: {_id: 1}, projection: {_id: 1}},
        [{_id: "New York"}]);
    assert.commandFailedWithCode(viewsDB.runCommand({find: "identityView", sort: {$natural: 1}}),
                                 ErrorCodes.InvalidPipelineOperator);

    // Negative batch size and limit should fail.
    assert.commandFailed(viewsDB.runCommand({find: "identityView", batchSize: -1}));
    assert.commandFailed(viewsDB.runCommand({find: "identityView", limit: -1}));

    // Comment should succeed.
    assert.commandWorked(
        viewsDB.runCommand({find: "identityView", filter: {}, comment: "views_find"}));

    // Views support find with explain.
    assert.commandWorked(viewsDB.identityView.find().explain());

    // Find with explicit explain modes works on a view.
    let explainPlan = assert.commandWorked(viewsDB.identityView.find().explain("queryPlanner"));
    assert.eq(explainPlan.stages[0].$cursor.queryPlanner.namespace, "views_find.coll");
    assert(!explainPlan.stages[0].$cursor.hasOwnProperty("executionStats"));

    explainPlan = assert.commandWorked(viewsDB.identityView.find().explain("executionStats"));
    assert.eq(explainPlan.stages[0].$cursor.queryPlanner.namespace, "views_find.coll");
    assert(explainPlan.stages[0].$cursor.hasOwnProperty("executionStats"));
    assert.eq(explainPlan.stages[0].$cursor.executionStats.nReturned, 5);
    assert(!explainPlan.stages[0].$cursor.executionStats.hasOwnProperty("allPlansExecution"));

    explainPlan = assert.commandWorked(viewsDB.identityView.find().explain("allPlansExecution"));
    assert.eq(explainPlan.stages[0].$cursor.queryPlanner.namespace, "views_find.coll");
    assert(explainPlan.stages[0].$cursor.hasOwnProperty("executionStats"));
    assert.eq(explainPlan.stages[0].$cursor.executionStats.nReturned, 5);
    assert(explainPlan.stages[0].$cursor.executionStats.hasOwnProperty("allPlansExecution"));

    // Only simple 0 or 1 projections are allowed on views.
    assert.writeOK(viewsDB.coll.insert({arr: [{x: 1}]}));
    assert.commandFailedWithCode(
        viewsDB.runCommand({find: "identityView", projection: {arr: {$elemMatch: {x: 1}}}}),
        ErrorCodes.InvalidPipelineOperator);

    // Views can support a "findOne" if singleBatch: true and limit: 1.
    assertFindResultEq({find: "identityView", filter: {state: "NY"}, singleBatch: true, limit: 1},
                       [{_id: "New York", state: "NY", pop: 7}]);
    assert.eq(viewsDB.identityView.findOne({_id: "San Francisco"}),
              {_id: "San Francisco", state: "CA", pop: 4});
}());