Files
mongo/jstests/core/arrayfind8.js
2016-05-28 17:55:12 -04:00

164 lines
5.9 KiB
JavaScript

// Matching behavior for $elemMatch applied to a top level element.
// SERVER-1264
// SERVER-4180
var debuggingEnabled = false;
t = db.jstests_arrayfind8;
t.drop();
function debug(x) {
if (debuggingEnabled) {
printjson(x);
}
}
/** Set index state for the test. */
function setIndexKey(key) {
indexKey = key;
indexSpec = {};
indexSpec[key] = 1;
}
setIndexKey('a');
/** Check that the query results match the documents in the 'expected' array. */
function assertResults(expected, query, context) {
debug(query);
assert.eq(expected.length, t.count(query), 'unexpected count in ' + context);
results = t.find(query).toArray();
for (i in results) {
found = false;
for (j in expected) {
if (friendlyEqual(expected[j], results[i].a)) {
found = true;
}
}
assert(found, 'unexpected result ' + results[i] + ' in ' + context);
}
}
/**
* Check matching for different query types.
* @param bothMatch - document matched by both standardQuery and elemMatchQuery
* @param elemMatch - document matched by elemMatchQuery but not standardQuery
* @param notElemMatch - document matched by standardQuery but not elemMatchQuery
*/
function checkMatch(bothMatch, elemMatch, nonElemMatch, standardQuery, elemMatchQuery, context) {
function mayPush(arr, elt) {
if (elt) {
arr.push(elt);
}
}
expectedStandardQueryResults = [];
mayPush(expectedStandardQueryResults, bothMatch);
mayPush(expectedStandardQueryResults, nonElemMatch);
assertResults(expectedStandardQueryResults, standardQuery, context + ' standard query');
expectedElemMatchQueryResults = [];
mayPush(expectedElemMatchQueryResults, bothMatch);
mayPush(expectedElemMatchQueryResults, elemMatch);
assertResults(expectedElemMatchQueryResults, elemMatchQuery, context + ' elemMatch query');
}
/**
* Check matching and for different query types.
* @param subQuery - part of a query, to be provided as is for a standard query and within a
* $elemMatch clause for a $elemMatch query
* @param bothMatch - document matched by both standardQuery and elemMatchQuery
* @param elemMatch - document matched by elemMatchQuery but not standardQuery
* @param notElemMatch - document matched by standardQuery but not elemMatchQuery
* @param additionalConstraints - additional query parameters not generated from @param subQuery
*/
function checkQuery(subQuery, bothMatch, elemMatch, nonElemMatch, additionalConstraints) {
t.drop();
additionalConstraints = additionalConstraints || {};
// Construct standard and elemMatch queries from subQuery.
firstSubQueryKey = Object.keySet(subQuery)[0];
if (firstSubQueryKey[0] == '$') {
standardQuery = {$and: [{a: subQuery}, additionalConstraints]};
} else {
// If the subQuery contains a field rather than operators, append to the 'a' field.
modifiedSubQuery = {};
modifiedSubQuery['a.' + firstSubQueryKey] = subQuery[firstSubQueryKey];
standardQuery = {$and: [modifiedSubQuery, additionalConstraints]};
}
elemMatchQuery = {$and: [{a: {$elemMatch: subQuery}}, additionalConstraints]};
debug(elemMatchQuery);
function maySave(aValue) {
if (aValue) {
debug({a: aValue});
t.save({a: aValue});
}
}
// Save all documents and check matching without indexes.
maySave(bothMatch);
maySave(elemMatch);
maySave(nonElemMatch);
checkMatch(bothMatch, elemMatch, nonElemMatch, standardQuery, elemMatchQuery, 'unindexed');
// Check matching and index bounds for a single key index.
t.drop();
maySave(bothMatch);
maySave(elemMatch);
// The nonElemMatch document is not tested here, as it will often make the index multikey.
t.ensureIndex(indexSpec);
checkMatch(bothMatch, elemMatch, null, standardQuery, elemMatchQuery, 'single key index');
// Check matching and index bounds for a multikey index.
// Now the nonElemMatch document is tested.
maySave(nonElemMatch);
// Force the index to be multikey.
t.save({a: [-1, -2]});
t.save({a: {b: [-1, -2]}});
checkMatch(bothMatch, elemMatch, nonElemMatch, standardQuery, elemMatchQuery, 'multikey index');
}
maxNumber = Infinity;
// Basic test.
checkQuery({$gt: 4}, [5]);
// Multiple constraints within a $elemMatch clause.
checkQuery({$gt: 4, $lt: 6}, [5], null, [3, 7]);
checkQuery({$gt: 4, $not: {$gte: 6}}, [5]);
checkQuery({$gt: 4, $not: {$ne: 6}}, [6]);
checkQuery({$gte: 5, $lte: 5}, [5], null, [4, 6]);
checkQuery({$in: [4, 6], $gt: 5}, [6], null, [4, 7]);
checkQuery({$regex: '^a'}, ['a']);
// Some constraints within a $elemMatch clause and other constraints outside of it.
checkQuery({$gt: 4}, [5], null, null, {a: {$lt: 6}});
checkQuery({$gte: 5}, [5], null, null, {a: {$lte: 5}});
checkQuery({$in: [4, 6]}, [6], null, null, {a: {$gt: 5}});
// Constraints in different $elemMatch clauses.
checkQuery({$gt: 4}, [5], null, null, {a: {$elemMatch: {$lt: 6}}});
checkQuery({$gt: 4}, [3, 7], null, null, {a: {$elemMatch: {$lt: 6}}});
checkQuery({$gte: 5}, [5], null, null, {a: {$elemMatch: {$lte: 5}}});
checkQuery({$in: [4, 6]}, [6], null, null, {a: {$elemMatch: {$gt: 5}}});
// TODO SERVER-1264
if (0) {
checkQuery({$elemMatch: {$in: [5]}}, null, [[5]], [5], null);
}
setIndexKey('a.b');
checkQuery({$elemMatch: {b: {$gte: 1, $lte: 1}}}, null, [[{b: 1}]], [{b: 1}], null);
checkQuery({$elemMatch: {b: {$gte: 1, $lte: 1}}}, null, [[{b: [0, 2]}]], [{b: [0, 2]}], null);
// Constraints for a top level (SERVER-1264 style) $elemMatch nested within a non top level
// $elemMatch.
checkQuery({b: {$elemMatch: {$gte: 1, $lte: 1}}}, [{b: [1]}]);
checkQuery({b: {$elemMatch: {$gte: 1, $lte: 4}}}, [{b: [1]}]);
checkQuery({b: {$elemMatch: {$gte: 1, $lte: 4}}}, [{b: [2]}], null, null, {'a.b': {$in: [2, 5]}});
checkQuery(
{b: {$elemMatch: {$in: [1, 2]}, $in: [2, 3]}}, [{b: [2]}], null, [{b: [1]}, {b: [3]}], null);