diff --git a/packages/minimongo/minimongo_tests.js b/packages/minimongo/minimongo_tests.js index ec3cf13f4a..92ce8e69f4 100644 --- a/packages/minimongo/minimongo_tests.js +++ b/packages/minimongo/minimongo_tests.js @@ -795,9 +795,12 @@ Tinytest.add("minimongo - selector_compiler", function (test) { match({$where: "_.isArray(this.a)"}, {a: []}); nomatch({$where: "_.isArray(this.a)"}, {a: 1}); + match({"dogs.0.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]}); + match({"dogs.1.name": "Rex"}, {dogs: [{name: "Fido"}, {name: "Rex"}]}); + nomatch({"dogs.1.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]}); + // XXX still needs tests: // - $elemMatch - // - people.2.name // - non-scalar arguments to $gt, $lt, etc }); diff --git a/packages/minimongo/selector.js b/packages/minimongo/selector.js index 5d1dfe7b99..e462b5e611 100644 --- a/packages/minimongo/selector.js +++ b/packages/minimongo/selector.js @@ -291,8 +291,6 @@ LocalCollection._selectorIsId = function (selector) { return (typeof selector === "string") || (typeof selector === "number"); }; -// XXX implement ordinal indexing: 'people.2.name' - // Given an arbitrary Mongo-style query selector, return an expression // that evaluates to true if the document in 'doc' matches the // selector, else false. @@ -396,19 +394,31 @@ LocalCollection._exprForKeypathPredicate = function (keypath, value, literals) { // drilling down through the dotted parts var ret = ''; var innermost = true; + var lastPartWasNumber = false; while (keyparts.length) { var part = keyparts.pop(); + var thisPartIsNumber = false; + if (/^\d+/.test(part)) { + part = +part; + thisPartIsNumber = true; + } var formal = keyparts.length ? "x" : "doc"; if (innermost) { ret = '(function(x){return ' + predcode + ';})(' + formal + '&&' + formal + '[' + JSON.stringify(part) + '])'; innermost = false; + } else if (lastPartWasNumber) { + // The last part was an array index, so if we find an array here we + // shouldn't search it! + ret = '(function(x){return ' + ret + ';})(' + formal + '&&' + formal + '[' + + JSON.stringify(part) + '])'; } else { - // for all but the innermost level of a dotted expression, - // if the runtime type is an array, search it + // If the runtime type is an array, search it, unless we're already at the + // innermost bit, or if the next part is a number (ie, an array index). ret = 'f._matches(' + formal + '&&' + formal + '[' + JSON.stringify(part) + '], function(x){return ' + ret + ';})'; } + lastPartWasNumber = thisPartIsNumber; } return ret;