mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Improve Mongo compatibility with $ne/$nin/$not and arrays.
Fixes #1451. We currently handle matches where the key has multiple values due to arrays in the document in two subtley different ways, depending on whether or not the array is in the last element of the keypath or not. (This is annoyingly necessary, at least in the current structure of how we compile selectors, due to various selectors differing in how they treat arrays.) The negative-style operators have "must match all values" semantics, but this was only being enforced when the branching was in the last element of the keypath. This commit semi-hackily applies those semantics for other branching too. We are still not 100% Mongo compatible (see XXX comment) but it's closer.
This commit is contained in:
@@ -427,6 +427,9 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
nomatch({a: {$ne: 1}}, {a: [1, 2]});
|
||||
nomatch({a: {$ne: 2}}, {a: [1, 2]});
|
||||
match({a: {$ne: 3}}, {a: [1, 2]});
|
||||
nomatch({'a.b': {$ne: 1}}, {a: [{b: 1}, {b: 2}]});
|
||||
nomatch({'a.b': {$ne: 2}}, {a: [{b: 1}, {b: 2}]});
|
||||
match({'a.b': {$ne: 3}}, {a: [{b: 1}, {b: 2}]});
|
||||
|
||||
nomatch({a: {$ne: {x: 1}}}, {a: {x: 1}});
|
||||
match({a: {$ne: {x: 1}}}, {a: {x: 2}});
|
||||
@@ -456,7 +459,9 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
nomatch({a: {$nin: [1, 2, 3]}}, {a: [2]}); // tested against mongodb
|
||||
nomatch({a: {$nin: [{x: 1}, {x: 2}, {x: 3}]}}, {a: [{x: 2}]});
|
||||
nomatch({a: {$nin: [1, 2, 3]}}, {a: [4, 2]});
|
||||
nomatch({'a.b': {$nin: [1, 2, 3]}}, {a: [{b:4}, {b:2}]});
|
||||
match({a: {$nin: [1, 2, 3]}}, {a: [4]});
|
||||
match({'a.b': {$nin: [1, 2, 3]}}, {a: [{b:4}]});
|
||||
|
||||
// $size
|
||||
match({a: {$size: 0}}, {a: []});
|
||||
@@ -564,7 +569,9 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
match({x: {$not: {$lt: 10, $gt: 7}}}, {x: 6});
|
||||
|
||||
match({x: {$not: {$gt: 7}}}, {x: [2, 3, 4]});
|
||||
match({'x.y': {$not: {$gt: 7}}}, {x: [{y:2}, {y:3}, {y:4}]});
|
||||
nomatch({x: {$not: {$gt: 7}}}, {x: [2, 3, 4, 10]});
|
||||
nomatch({'x.y': {$not: {$gt: 7}}}, {x: [{y:2}, {y:3}, {y:4}, {y:10}]});
|
||||
|
||||
match({x: {$not: /a/}}, {x: "dog"});
|
||||
nomatch({x: {$not: /a/}}, {x: "cat"});
|
||||
|
||||
@@ -551,9 +551,25 @@ var compileDocumentSelector = function (docSelector) {
|
||||
perKeySelectors.push(function (doc) {
|
||||
var branchValues = lookUpByIndex(doc);
|
||||
// We apply the selector to each "branched" value and return true if any
|
||||
// match. This isn't 100% consistent with MongoDB; eg, see:
|
||||
// https://jira.mongodb.org/browse/SERVER-8585
|
||||
return _.any(branchValues, valueSelectorFunc);
|
||||
// match. However, for "negative" selectors like $ne or $not we actually
|
||||
// require *all* elements to match.
|
||||
//
|
||||
// This is because {'x.tag': {$ne: "foo"}} applied to {x: [{tag: 'foo'},
|
||||
// {tag: 'bar'}]} should NOT match even though there is a branch that
|
||||
// matches. (This matches the fact that $ne uses a negated
|
||||
// _anyIfArrayPlus, for when the last level of the key is the array,
|
||||
// which deMorgans into an 'all'.)
|
||||
//
|
||||
// XXX This isn't 100% consistent with MongoDB in 'null' cases:
|
||||
// https://jira.mongodb.org/browse/SERVER-8585
|
||||
// XXX this still isn't right. consider {a: {$ne: 5, $gt: 6}}. the
|
||||
// $ne needs to use the "all" logic and the $gt needs the "any"
|
||||
// logic
|
||||
var combiner = (subSelector &&
|
||||
(subSelector.$not || subSelector.$ne ||
|
||||
subSelector.$nin))
|
||||
? _.all : _.any;
|
||||
return combiner(branchValues, valueSelectorFunc);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user