mirror of https://github.com/mongodb/mongo
153 lines
3.9 KiB
JavaScript
153 lines
3.9 KiB
JavaScript
// Tests the ability of the $_internalJsEmit expression to access javascript scope explicitly
|
|
// specified in runtimeConstants.
|
|
//
|
|
// Do not run in sharded passthroughs since 'runtimeConstants' is disallowed on mongos.
|
|
// Must also set 'fromRouter: true' as otherwise 'runtimeConstants' is disallowed on mongod.
|
|
// @tags: [
|
|
// assumes_against_mongod_not_mongos,
|
|
// requires_scripting,
|
|
// requires_fcv_81,
|
|
// ]
|
|
import {resultsEq} from "jstests/aggregation/extras/utils.js";
|
|
|
|
const coll = db.js_emit_with_scope;
|
|
coll.drop();
|
|
|
|
const weights = {
|
|
wood: 5,
|
|
chuck: 2,
|
|
could: 0,
|
|
};
|
|
|
|
let constants = {
|
|
localNow: new Date(),
|
|
clusterTime: new Timestamp(0, 0),
|
|
jsScope: {weights: weights},
|
|
};
|
|
|
|
function fmap() {
|
|
for (let word of this.text.split(" ")) {
|
|
emit(word, weights[word]);
|
|
}
|
|
}
|
|
|
|
let pipeline = [
|
|
{
|
|
$project: {
|
|
emits: {
|
|
$_internalJsEmit: {
|
|
this: "$$ROOT",
|
|
eval: fmap,
|
|
},
|
|
},
|
|
_id: 0,
|
|
},
|
|
},
|
|
{$unwind: "$emits"},
|
|
{$replaceRoot: {newRoot: "$emits"}},
|
|
];
|
|
|
|
assert.commandWorked(coll.insert({text: "wood chuck could chuck wood"}));
|
|
|
|
let results = coll.aggregate(pipeline, {cursor: {}, runtimeConstants: constants, fromRouter: true}).toArray();
|
|
assert(
|
|
resultsEq(
|
|
results,
|
|
[
|
|
{k: "wood", v: weights["wood"]},
|
|
{k: "chuck", v: weights["chuck"]},
|
|
{k: "could", v: weights["could"]},
|
|
{k: "chuck", v: weights["chuck"]},
|
|
{k: "wood", v: weights["wood"]},
|
|
],
|
|
results,
|
|
),
|
|
);
|
|
|
|
//
|
|
// Test that the scope variables are mutable from within a user-defined javascript function.
|
|
//
|
|
pipeline[0].$project.emits.$_internalJsEmit.eval = function () {
|
|
for (let word of this.text.split(" ")) {
|
|
emit(word, weights[word]);
|
|
weights[word] += 1;
|
|
}
|
|
};
|
|
|
|
results = coll.aggregate(pipeline, {cursor: {}, runtimeConstants: constants, fromRouter: true}).toArray();
|
|
assert(
|
|
resultsEq(
|
|
results,
|
|
[
|
|
{k: "wood", v: weights["wood"]},
|
|
{k: "chuck", v: weights["chuck"]},
|
|
{k: "could", v: weights["could"]},
|
|
{k: "chuck", v: weights["chuck"] + 1},
|
|
{k: "wood", v: weights["wood"] + 1},
|
|
],
|
|
results,
|
|
),
|
|
);
|
|
|
|
//
|
|
// Test that the jsScope is allowed to have any number of fields.
|
|
//
|
|
/* eslint-disable */
|
|
constants.jsScope.multiplier = 5;
|
|
pipeline[0].$project.emits.$_internalJsEmit.eval = function () {
|
|
for (let word of this.text.split(" ")) {
|
|
emit(word, weights[word] * multiplier);
|
|
}
|
|
};
|
|
/* eslint-enable */
|
|
|
|
results = coll.aggregate(pipeline, {cursor: {}, runtimeConstants: constants, fromRouter: true}).toArray();
|
|
assert(
|
|
resultsEq(
|
|
results,
|
|
[
|
|
{k: "wood", v: weights["wood"] * 5},
|
|
{k: "chuck", v: weights["chuck"] * 5},
|
|
{k: "could", v: weights["could"] * 5},
|
|
{k: "chuck", v: weights["chuck"] * 5},
|
|
{k: "wood", v: weights["wood"] * 5},
|
|
],
|
|
results,
|
|
),
|
|
);
|
|
constants.jsScope = {};
|
|
pipeline[0].$project.emits.$_internalJsEmit.eval = function () {
|
|
for (let word of this.text.split(" ")) {
|
|
emit(word, 1);
|
|
}
|
|
};
|
|
results = coll.aggregate(pipeline, {cursor: {}, runtimeConstants: constants, fromRouter: true}).toArray();
|
|
assert(
|
|
resultsEq(
|
|
results,
|
|
[
|
|
{k: "wood", v: 1},
|
|
{k: "chuck", v: 1},
|
|
{k: "could", v: 1},
|
|
{k: "chuck", v: 1},
|
|
{k: "wood", v: 1},
|
|
],
|
|
results,
|
|
),
|
|
);
|
|
|
|
//
|
|
// Test that the command fails if the jsScope is not an object.
|
|
//
|
|
constants.jsScope = "you cant do this";
|
|
assert.commandFailedWithCode(
|
|
db.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: pipeline,
|
|
cursor: {},
|
|
runtimeConstants: constants,
|
|
fromRouter: true,
|
|
}),
|
|
ErrorCodes.TypeMismatch,
|
|
);
|