125 lines
4.2 KiB
JavaScript
125 lines
4.2 KiB
JavaScript
/**
|
|
* With standard $lookup syntax, the "from" collection is always interpreted to be in the same
|
|
* database the aggregate command is run on. Additionally, the merging is always done on the primary
|
|
* shard for the database.
|
|
*
|
|
* This tests alternative $lookup syntax that supports reading from an unsharded collection that has
|
|
* identical contents across all shards (specifically config.cache.chunks.* namespaces). With the
|
|
* alternative syntax, $lookup behavior changes and it is run locally on each shard rather than
|
|
* merged on the primary shard for the database.
|
|
*
|
|
* Alternative $lookup syntax:
|
|
* {$lookup: {from: {db:<>, coll:<>},...}}
|
|
*/
|
|
import {assertErrorCode} from "jstests/aggregation/extras/utils.js";
|
|
import {DiscoverTopology} from "jstests/libs/discover_topology.js";
|
|
import {ShardingTest} from "jstests/libs/shardingtest.js";
|
|
import {flushRoutersAndRefreshShardMetadata} from "jstests/sharding/libs/sharded_transactions_helpers.js";
|
|
|
|
const st = new ShardingTest({shards: 2});
|
|
const dbName = jsTestName();
|
|
const collName = "foo";
|
|
let chunksCollName;
|
|
|
|
const shard0DB = st.shard0.getDB(dbName);
|
|
const shard1DB = st.shard1.getDB(dbName);
|
|
const sourceCollection = st.s0.getDB(dbName)[collName];
|
|
|
|
// Sets up the data for $lookup on config.cache.chunks.* namespaces.
|
|
const setUp = () => {
|
|
sourceCollection.drop();
|
|
// Set up sourceCollection to be sharded on {x:1} and to have the following distribution:
|
|
// shard0: [MinKey, 0)
|
|
// shard1: [0, MaxKey)
|
|
st.shardColl(sourceCollection, {x: 1}, {x: 0}, {x: 0}, dbName);
|
|
|
|
// Insert a corresponding entry in sourceCollection for each document in
|
|
// config.cache.chunks.collUuid.
|
|
assert.commandWorked(sourceCollection.insert({x: MinKey}));
|
|
assert.commandWorked(sourceCollection.insert({x: 0}));
|
|
|
|
const collNs = dbName + "." + collName;
|
|
const collEntry = st.config.collections.findOne({_id: collNs});
|
|
chunksCollName = "cache.chunks." + collNs;
|
|
flushRoutersAndRefreshShardMetadata(st, {collNs});
|
|
};
|
|
|
|
// $lookup alternative syntax only supports reading 'from' config.cache.chunks.* namespaces.
|
|
const invalidLookups = [
|
|
{
|
|
$lookup: {
|
|
from: {db: "config", coll: "validDB.WithInvalid.collection"},
|
|
localField: "x",
|
|
foreignField: "_id.x",
|
|
as: "results",
|
|
},
|
|
},
|
|
{
|
|
$lookup: {
|
|
from: {db: "wrongDB", coll: `${chunksCollName}`},
|
|
localField: "x",
|
|
foreignField: "_id.x",
|
|
as: "results",
|
|
},
|
|
},
|
|
{
|
|
$lookup: {
|
|
from: {db: "config", coll: "validDB.LetLookup.invalidCollectionName"},
|
|
let: {x_field: "$x"},
|
|
pipeline: [{$match: {$expr: {$eq: ["$_id.x", "$$x_field"]}}}],
|
|
as: "results",
|
|
},
|
|
},
|
|
{
|
|
$lookup: {
|
|
from: {db: "wrongDBWithLet", coll: `${chunksCollName}`},
|
|
let: {x_field: "$x"},
|
|
pipeline: [{$match: {$expr: {$eq: ["$_id.x", "$$x_field"]}}}],
|
|
as: "results",
|
|
},
|
|
},
|
|
];
|
|
|
|
invalidLookups.forEach((testCase) => {
|
|
assertErrorCode(
|
|
sourceCollection,
|
|
[testCase],
|
|
ErrorCodes.FailedToParse,
|
|
`Expected $lookup to fail. Original command: ${tojson(testCase)}`,
|
|
);
|
|
});
|
|
|
|
const nodeList = DiscoverTopology.findNonConfigNodes(st.s);
|
|
|
|
// Tests that $lookup from config.cache.chunks.* yields the expected results.
|
|
const testLookupFromConfigCacheChunks = (lookupAgg) => {
|
|
jsTestLog(`Running test on lookup: ${tojson(lookupAgg)}`);
|
|
|
|
const results = sourceCollection.aggregate(lookupAgg).toArray();
|
|
results.forEach((res) => {
|
|
assert.eq(res.results.length, 1, `Failed with results ${tojson(results)}`);
|
|
});
|
|
};
|
|
|
|
setUp();
|
|
const lookupBasic = {
|
|
$lookup: {
|
|
from: {db: "config", coll: `${chunksCollName}`},
|
|
localField: "x",
|
|
foreignField: "_id.x",
|
|
as: "results",
|
|
},
|
|
};
|
|
testLookupFromConfigCacheChunks(lookupBasic);
|
|
|
|
const lookupLet = {
|
|
$lookup: {
|
|
from: {db: "config", coll: `${chunksCollName}`},
|
|
let: {x_field: "$x"},
|
|
pipeline: [{$match: {$expr: {$eq: ["$_id.x", "$$x_field"]}}}],
|
|
as: "results",
|
|
},
|
|
};
|
|
testLookupFromConfigCacheChunks(lookupLet);
|
|
st.stop();
|