mongo/jstests/aggregation/expressions/in.js

210 lines
5.5 KiB
JavaScript

// SERVER-6146 introduced the $in expression to aggregation. In this file, we test the functionality
// and error cases of the expression.
// @tags: [
// assumes_no_implicit_collection_creation_after_drop,
// ]
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
(function() {
"use strict";
const caseInsensitive = {
locale: "en_US",
strength: 2
};
var coll = db.in;
coll.drop();
function testExpression(options) {
coll.drop();
testExpressionInternal(options);
}
function testExpressionHashIndex(options) {
coll.drop();
assert.commandWorked(coll.createIndex({elementField: "hashed"}));
testExpressionInternal(options);
}
function testExpressionCollectionCollation(options, collationSpec) {
coll.drop();
assert.commandWorked(db.createCollection(coll.getName(), {collation: collationSpec}));
testExpressionInternal(options);
}
function testExpressionInternal(options) {
var pipeline = {$project: {included: {$in: ["$elementField", {$literal: options.array}]}}};
assert.commandWorked(coll.insert({elementField: options.element}));
var res = coll.aggregate(pipeline).toArray();
assert.eq(res.length, 1);
assert.eq(res[0].included, options.elementIsIncluded);
if (options.queryFormShouldBeEquivalent) {
var query = {elementField: {$in: options.array}};
res = coll.find(query).toArray();
if (options.elementIsIncluded) {
assert.eq(res.length, 1);
} else {
assert.eq(res.length, 0);
}
}
}
testExpression(
{element: 1, array: [1, 2, 3], elementIsIncluded: true, queryFormShouldBeEquivalent: true});
testExpression({
element: "A",
array: ["a", "A", "a"],
elementIsIncluded: true,
queryFormShouldBeEquivalent: true
});
testExpression({
element: {a: 1},
array: [{b: 1}, 2],
elementIsIncluded: false,
queryFormShouldBeEquivalent: true
});
testExpression(
{element: {a: 1}, array: [{a: 1}], elementIsIncluded: true, queryFormShouldBeEquivalent: true});
testExpression({
element: [1, 2],
array: [[2, 1]],
elementIsIncluded: false,
queryFormShouldBeEquivalent: true
});
testExpression(
{element: [1, 2], array: [[1, 2]], elementIsIncluded: true, queryFormShouldBeEquivalent: true});
// Test $in with duplicated target element.
testExpression({
element: 7,
array: [3, 5, 7, 7, 9],
elementIsIncluded: true,
queryFormShouldBeEquivalent: true
});
// Test $in with other element within array duplicated.
testExpression({
element: 7,
array: [3, 5, 7, 9, 9],
elementIsIncluded: true,
queryFormShouldBeEquivalent: true
});
// Test $in on unsorted array.
testExpression({
element: 7,
array: [3, 10, 5, 7, 8, 9],
elementIsIncluded: true,
queryFormShouldBeEquivalent: true
});
// Test matching $in on unsorted array with duplicates.
testExpression({
element: 7,
array: [7, 10, 7, 10, 2, 5, 3, 7],
elementIsIncluded: true,
queryFormShouldBeEquivalent: true
});
// Test non-matching $in on unsorted array with duplicates.
testExpression({
element: 8,
array: [10, 7, 2, 5, 3],
elementIsIncluded: false,
queryFormShouldBeEquivalent: true
});
// Test $in with success due to collation on source collection.
testExpressionCollectionCollation({
element: "abcd",
array: ["aBcD", "ABCD"],
elementIsIncluded: true,
queryFormShouldBeEquivalent: true
},
caseInsensitive);
// Test $in with a source collection that has a hash index on the relevant field.
testExpressionHashIndex({
element: 5,
array: [10, 7, 2, 5, 3],
elementIsIncluded: true,
queryFormShouldBeEquivalent: true
});
testExpression(
{element: 1, array: [], elementIsIncluded: false, queryFormShouldBeEquivalent: true});
// Aggregation's $in has parity with query's $in except with regexes matching string values and
// equality semantics with array values.
testExpression({
element: "abc",
array: [/a/, /b/, /c/],
elementIsIncluded: false,
queryFormShouldBeEquivalent: false
});
testExpression({
element: /a/,
array: ["a", "b", "c"],
elementIsIncluded: false,
queryFormShouldBeEquivalent: false
});
testExpression(
{element: [], array: [1, 2, 3], elementIsIncluded: false, queryFormShouldBeEquivalent: false});
testExpression(
{element: [1], array: [1, 2, 3], elementIsIncluded: false, queryFormShouldBeEquivalent: false});
testExpression({
element: [1, 2],
array: [1, 2, 3],
elementIsIncluded: false,
queryFormShouldBeEquivalent: false
});
coll.drop();
coll.insert({});
var pipeline = {$project: {included: {$in: [[1, 2], 1]}}};
assertErrorCode(coll, pipeline, 40081, "$in requires an array as a second argument");
pipeline = {
$project: {included: {$in: [1, null]}}
};
assertErrorCode(coll, pipeline, 40081, "$in requires an array as a second argument");
pipeline = {
$project: {included: {$in: [1, "$notAField"]}}
};
assertErrorCode(coll, pipeline, 40081, "$in requires an array as a second argument");
pipeline = {
$project: {included: {$in: null}}
};
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
pipeline = {
$project: {included: {$in: [1]}}
};
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
pipeline = {
$project: {included: {$in: []}}
};
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
pipeline = {
$project: {included: {$in: [1, 2, 3]}}
};
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
}());