Files
mongo/jstests/aggregation/sources/graphLookup/basic.js

185 lines
6.1 KiB
JavaScript

// In MongoDB 3.4, $graphLookup was introduced. In this file, we test basic behavior and correctness
// of the stage.
(function() {
"use strict";
var local = db.local;
var foreign = db.foreign;
local.drop();
foreign.drop();
// Ensure a $graphLookup works even if one of the involved collections doesn't exist.
const basicGraphLookup = {
$graphLookup: {
from: "foreign",
startWith: "$starting",
connectFromField: "from",
connectToField: "to",
as: "results"
}
};
assert.eq(
local.aggregate([basicGraphLookup]).toArray().length,
0,
"expected an empty result set for a $graphLookup with non-existent local and foreign " +
"collections");
assert.writeOK(foreign.insert({}));
assert.eq(local.aggregate([basicGraphLookup]).toArray().length,
0,
"expected an empty result set for a $graphLookup on a non-existent local collection");
local.drop();
foreign.drop();
assert.writeOK(local.insert({_id: 0}));
assert.eq(local.aggregate([basicGraphLookup]).toArray(),
[{_id: 0, results: []}],
"expected $graphLookup to succeed with a non-existent foreign collection");
local.drop();
foreign.drop();
var bulk = foreign.initializeUnorderedBulkOp();
for (var i = 0; i < 100; i++) {
bulk.insert({_id: i, neighbors: [i - 1, i + 1]});
}
assert.writeOK(bulk.execute());
assert.writeOK(local.insert({starting: 50}));
// Perform a simple $graphLookup and ensure it retrieves every result.
var res = local
.aggregate({
$graphLookup: {
from: "foreign",
startWith: "$starting",
connectFromField: "neighbors",
connectToField: "_id",
as: "integers"
}
})
.toArray()[0];
assert.eq(res.integers.length, 100);
// Perform a $graphLookup and ensure it respects "maxDepth".
res = local
.aggregate({
$graphLookup: {
from: "foreign",
startWith: "$starting",
connectFromField: "neighbors",
connectToField: "_id",
maxDepth: 5,
as: "integers"
}
})
.toArray()[0];
// At depth zero, we retrieve one integer, and two for every depth thereafter.
assert.eq(res.integers.length, 11);
// Perform a $graphLookup and ensure it properly evaluates "startWith".
res = local
.aggregate({
$graphLookup: {
from: "foreign",
startWith: {$add: ["$starting", 3]},
connectFromField: "neighbors",
connectToField: "_id",
maxDepth: 0,
as: "integers"
}
})
.toArray()[0];
assert.eq(res.integers.length, 1);
assert.eq(res.integers[0]._id, 53);
// Perform a $graphLookup and ensure it properly expands "startWith".
res = local
.aggregate({
$graphLookup: {
from: "foreign",
startWith: {$literal: [1, 2, 3]},
connectFromField: "neighbors",
connectToField: "_id",
maxDepth: 0,
as: "integers"
}
})
.toArray()[0];
assert.eq(res.integers.length, 3);
// $graphLookup should not recurse when the 'connectFromField' is missing. However, if it
// mistakenly does, then it would look for a 'connectToField' value of null. In order to prevent
// regressions, we insert a document with a 'connectToField' value of null, then perform a
// $graphLookup, and ensure that we do not find the erroneous document.
assert.writeOK(foreign.remove({_id: 51}));
assert.writeOK(foreign.insert({_id: 51}));
assert.writeOK(foreign.insert({_id: null, neighbors: [50, 52]}));
res = local
.aggregate({
$graphLookup: {
from: "foreign",
startWith: "$starting",
connectFromField: "neighbors",
connectToField: "_id",
as: "integers"
}
})
.toArray()[0];
// Our result should be missing the values with _id from 52 to 99.
assert.eq(res.integers.length, 52);
// Perform a $graphLookup and ensure we don't go into an infinite loop when our graph is cyclic.
assert.writeOK(foreign.remove({_id: {$in: [null, 51]}}));
assert.writeOK(foreign.insert({_id: 51, neighbors: [50, 52]}));
assert.writeOK(foreign.update({_id: 99}, {$set: {neighbors: [98, 0]}}));
assert.writeOK(foreign.update({_id: 0}, {$set: {neighbors: [99, 1]}}));
res = local
.aggregate({
$graphLookup: {
from: "foreign",
startWith: "$starting",
connectFromField: "neighbors",
connectToField: "_id",
as: "integers"
}
})
.toArray()[0];
assert.eq(res.integers.length, 100);
// Perform a $graphLookup and ensure that "depthField" is properly populated.
res = local
.aggregate({
$graphLookup: {
from: "foreign",
startWith: "$starting",
connectFromField: "neighbors",
connectToField: "_id",
depthField: "distance",
as: "integers"
}
})
.toArray()[0];
assert.eq(res.integers.length, 100);
res.integers.forEach(function(n) {
assert.eq(n.distance, Math.abs(50 - n._id));
});
}());