summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Wahlin <james@mongodb.com>2019-01-30 16:33:34 -0500
committerJames Wahlin <james@mongodb.com>2019-01-31 12:30:43 -0500
commita2c0f15d6dc9fcda389b18b54287c4fcb5be44cd (patch)
tree625a847873e1003ef297dc0dd8ac97f48cfeebfb
parent01d84b2565fc9ea9626a55dcf1f3f817968088f2 (diff)
downloadmongo-a2c0f15d6dc9fcda389b18b54287c4fcb5be44cd.tar.gz
SERVER-13779 Allow $not to be applied to $regex
-rw-r--r--jstests/core/not2.js81
-rw-r--r--src/mongo/db/matcher/expression_parser.cpp6
2 files changed, 41 insertions, 46 deletions
diff --git a/jstests/core/not2.js b/jstests/core/not2.js
index 21e8d9aa9c4..610d79c4d8f 100644
--- a/jstests/core/not2.js
+++ b/jstests/core/not2.js
@@ -6,14 +6,12 @@
const coll = db.jstests_not2;
coll.drop();
- function check(query, expected, size) {
- if (size === undefined) {
- size = 1;
- }
- assert.eq(size, coll.find(query).itcount(), tojson(query));
- if (size > 0) {
- const cursor = coll.find(query).sort({i: 1});
- assert.eq(expected, cursor.toArray()[0].i, tojson(query));
+ function check(query, expected) {
+ const resultList = coll.find(query).sort({i: 1}).toArray();
+ assert.eq(expected.length, resultList.length, query);
+
+ for (let x = 0; x < expected.length; ++x) {
+ assert.eq(expected[x], resultList[x].i, query);
}
}
@@ -30,53 +28,56 @@
// TODO SERVER-12735: We currently do not handle double negatives during query
// canonicalization.
fail({i: {$not: {$not: "a"}}});
- check({i: {$not: {$not: {$gt: "a"}}}}, "b");
+ check({i: {$not: {$not: {$gt: "a"}}}}, ["b"]);
fail({i: {$not: "a"}});
fail({i: {$not: {$ref: "foo"}}});
fail({i: {$not: {}}});
- check({i: {$gt: "a"}}, "b");
- check({i: {$not: {$gt: "a"}}}, "a");
- check({i: {$not: {$ne: "a"}}}, "a");
- check({i: {$not: {$gte: "b"}}}, "a");
- check({i: {$exists: true}}, "a", 2);
- check({i: {$not: {$exists: true}}}, "", 0);
- check({j: {$not: {$exists: false}}}, "", 0);
- check({j: {$not: {$exists: true}}}, "a", 2);
- check({i: {$not: {$in: ["a"]}}}, "b");
- check({i: {$not: {$in: ["a", "b"]}}}, "", 0);
- check({i: {$not: {$in: ["g"]}}}, "a", 2);
- check({i: {$not: {$nin: ["a"]}}}, "a");
- check({i: {$not: /a/}}, "b");
- check({i: {$not: /(a|b)/}}, "", 0);
- check({i: {$not: /a/, $regex: "a"}}, "", 0);
- check({i: {$not: /aa/}}, "a", 2);
- fail({i: {$not: {$regex: "a"}}});
+ check({i: {$gt: "a"}}, ["b"]);
+ check({i: {$not: {$gt: "a"}}}, ["a"]);
+ check({i: {$not: {$ne: "a"}}}, ["a"]);
+ check({i: {$not: {$gte: "b"}}}, ["a"]);
+ check({i: {$exists: true}}, ["a", "b"]);
+ check({i: {$not: {$exists: true}}}, []);
+ check({j: {$not: {$exists: false}}}, []);
+ check({j: {$not: {$exists: true}}}, ["a", "b"]);
+ check({i: {$not: {$in: ["a"]}}}, ["b"]);
+ check({i: {$not: {$in: ["a", "b"]}}}, []);
+ check({i: {$not: {$in: ["g"]}}}, ["a", "b"]);
+ check({i: {$not: {$nin: ["a"]}}}, ["a"]);
+ check({i: {$not: /a/}}, ["b"]);
+ check({i: {$not: /(a|b)/}}, []);
+ check({i: {$not: /a/, $regex: "a"}}, []);
+ check({i: {$not: /aa/}}, ["a", "b"]);
+ check({i: {$not: {$regex: "a"}}}, ["b"]);
+ check({i: {$not: {$regex: "A", $options: "i"}}}, ["b"]);
+ check({i: {$not: {$regex: "[ab]"}}}, []);
+ check({i: {$not: {$regex: "^foo"}}}, ["a", "b"]);
fail({i: {$not: {$options: "a"}}});
- check({i: {$type: 2}}, "a", 2);
- check({i: {$not: {$type: 1}}}, "a", 2);
- check({i: {$not: {$type: 2}}}, "", 0);
+ check({i: {$type: 2}}, ["a", "b"]);
+ check({i: {$not: {$type: 1}}}, ["a", "b"]);
+ check({i: {$not: {$type: 2}}}, []);
assert.writeOK(coll.remove({}));
assert.writeOK(coll.insert({i: 1}));
- check({i: {$not: {$mod: [5, 1]}}}, null, 0);
- check({i: {$mod: [5, 2]}}, null, 0);
- check({i: {$not: {$mod: [5, 2]}}}, 1, 1);
+ check({i: {$not: {$mod: [5, 1]}}}, []);
+ check({i: {$mod: [5, 2]}}, []);
+ check({i: {$not: {$mod: [5, 2]}}}, [1]);
assert.writeOK(coll.remove({}));
assert.writeOK(coll.insert({i: ["a", "b"]}));
- check({i: {$not: {$size: 2}}}, null, 0);
- check({i: {$not: {$size: 3}}}, ["a", "b"]);
- check({i: {$not: {$gt: "a"}}}, null, 0);
- check({i: {$not: {$gt: "c"}}}, ["a", "b"]);
- check({i: {$not: {$all: ["a", "b"]}}}, null, 0);
- check({i: {$not: {$all: ["c"]}}}, ["a", "b"]);
+ check({i: {$not: {$size: 2}}}, []);
+ check({i: {$not: {$size: 3}}}, [["a", "b"]]);
+ check({i: {$not: {$gt: "a"}}}, []);
+ check({i: {$not: {$gt: "c"}}}, [["a", "b"]]);
+ check({i: {$not: {$all: ["a", "b"]}}}, []);
+ check({i: {$not: {$all: ["c"]}}}, [["a", "b"]]);
assert.writeOK(coll.remove({}));
assert.writeOK(coll.insert({i: [{j: "a"}]}));
assert.writeOK(coll.insert({i: [{j: "b"}]}));
- check({i: {$not: {$elemMatch: {j: "a"}}}}, [{j: "b"}]);
- check({i: {$not: {$elemMatch: {j: "f"}}}}, [{j: "a"}], 2);
+ check({i: {$not: {$elemMatch: {j: "a"}}}}, [[{j: "b"}]]);
+ check({i: {$not: {$elemMatch: {j: "f"}}}}, [[{j: "a"}], [{j: "b"}]]);
}
// Run the test without any index.
diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp
index 8a055626399..e75fa98d8e0 100644
--- a/src/mongo/db/matcher/expression_parser.cpp
+++ b/src/mongo/db/matcher/expression_parser.cpp
@@ -1372,12 +1372,6 @@ StatusWithMatchExpression parseNot(StringData name,
return parseStatus;
}
- for (size_t i = 0; i < theAnd->numChildren(); i++) {
- if (theAnd->getChild(i)->matchType() == MatchExpression::REGEX) {
- return {ErrorCodes::BadValue, "$not cannot have a regex"};
- }
- }
-
return {stdx::make_unique<NotMatchExpression>(theAnd.release())};
}