Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect matching of deeply nested values and whole objects #36

Closed
kofrasa opened this issue Dec 1, 2016 · 1 comment
Closed

Incorrect matching of deeply nested values and whole objects #36

kofrasa opened this issue Dec 1, 2016 · 1 comment
Labels

Comments

@kofrasa
Copy link
Owner

kofrasa commented Dec 1, 2016

From experiments, MongoDB only allows one level of nesting when matching values in an array without explicit indexes in the selector.

> db.test.insert({
...     key0: [{
...       key1: [[[{key2: [{a:"value2"}, {a: "dummy"}, {b:20}]}]], {"key2": "value"}],
...       key1a: {key2a: "value2a"}
...     }]
...   })
WriteResult({ "nInserted" : 1 })
> // Test: query deeply nested value
> // 1. specify no array index
> db.test.find({"key0.key1.key2.a": "value2"}) // no match
>
> // 2. specify partial array index selector for nested value
> db.test.find({"key0.key1.0.key2.a": "value2"}) // no match
>
> // 3. specify full array index selector to deeply nested value
> db.test.find({"key0.key1.0.0.key2.a": "value2"}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }

> // Test: query shallow nested value
> // 1. specify no array index
> db.test.find({"key0.key1.key2": "value"}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }
>
> // 2. specify array index
> db.test.find({"key0.key1.1.key2": "value"}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }

Matching whole object is also broken.

> // Test: match whole objects
> db.test.find({"key0.key1": [[{key2: [{a:"value2"}, {a: "dummy"}, {b:20}]}]]}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }

> db.test.find({"key0.key1.0": [[{key2: [{a:"value2"}, {a: "dummy"}, {b:20}]}]]}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }

> db.test.find({"key0.key1.0.0": [{key2: [{a:"value2"}, {a: "dummy"}, {b:20}]}]}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }
>
> db.test.find({"key0.key1.0.0.key2": [{a:"value2"}, {a: "dummy"}, {b:20}]}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }
>
> db.test.find({"key0.key1.0.0.key2": {b:20}}) // match
{ "_id" : ObjectId("583fad3a1828419a48d35fe1"), "key0" : [ { "key1" : [ [ [ { "key2" : [ { "a" : "value2" }, { "a" : "dummy" }, { "b" : 20 } ] } ] ], { "key2" : "value" } ], "key1a" : { "key2a" : "value2a" } } ] }

Tested with MongoDB@v3.2.5.

We currently do not handle these cases correctly. Using the sample data.

var Mingo = require("mingo");
var _ = Mingo._internal();

var fixtures = [
    [{"key0.key1.key2.a": "value2"}, [], "should not match without array index selector to nested value "],
    [{"key0.key1.0.key2.a": "value2"}, [], "should not match without enough depth for array index selector to nested value"],
    [{"key0.key1.0.0.key2.a": "value2"}, data, "should match with full array index selector to deeply nested value"],
    [{"key0.key1.0.0.key2": {b:20}}, data, "should match with array index selector to nested value at depth 1"],
    [{"key0.key1.1.key2": "value"}, data, "should match with full array index selector to nested value"],
    [{"key0.key1.key2": "value"}, data, "should match without array index selector to nested value at depth 1"],
    [{"key0.key1.1.key2": "value"}, data, "should match shallow nested value with array index selector"]
  ];

console.log("#Test 1: matching deep nested objects");
fixtures.forEach(function (f) {
   var query = f[0],
       expect = f[1],
       msg = f[2];
   var result = Mingo.find(data, query).all();
   console.log(_.isEqual(result, expect) + "> " + msg);
});
console.log(">>>>>>>>>>>>> finish test 1 <<<<<<<<<<<<<");

console.log("#Test 2: matching whole objects");
fixtures = [
    [{"key0.key1": [[{key2: [{a:"value2"}, {a: "dummy"}, {b:20}]}]]}, "should match full key selector"],
    [{"key0.key1.0": [[{key2: [{a:"value2"}, {a: "dummy"}, {b:20}]}]]}, "should match with key<-->index selector"],
    [{"key0.key1.0.0": [{key2: [{a:"value2"}, {a: "dummy"}, {b:20}]}]}, "should match with key<-->multi-index selector"],
    [{"key0.key1.0.0.key2": [{a:"value2"}, {a: "dummy"}, {b:20}]}, "should match with key<-->multi-index<-->key selector"]
  ];

fixtures.forEach(function (f) {
   var query = f[0],
       msg = f[1];
   var result = Mingo.find(data, query).all();
   console.log(_.isEqual(result, data) + "> " + msg);
});
console.log(">>>>>>>>>>>>> finish test 2 <<<<<<<<<<<<<");
// output below
/* #Test 1: matching deep nested objects 
false> should not match without array index selector to nested value
false> should not match without enough depth for array index selector to nested value
true> should match with full array index selector to deeply nested value
true> should match with array index selector to nested value at depth 1
false> should match with full array index selector to nested value
true> should match without array index selector to nested value at depth 1
false> should match shallow nested value with array index selector
>>>>>>>>>>>>> finish test 1 <<<<<<<<<<<<<
#Test 2: matching whole objects

/Users/francis/workspace/mingo/mingo.js:505
        throw new Error("Invalid query operator '" + operator + "' detected");
              ^
Error: Invalid query operator '0' detected
    at Object.Mingo.Query._processOperator (/Users/francis/workspace/mingo/mingo.js:505:15)
    at Object.Mingo.Query._compile (/Users/francis/workspace/mingo/mingo.js:493:22)
    at Object.Mingo.Query (/Users/francis/workspace/mingo/mingo.js:472:10)
    at Object.Mingo.find (/Users/francis/workspace/mingo/mingo.js:820:13)
    at /Users/francis/workspace/mingo/test/test.js:44:23
    at Array.forEach (native)
    at Object.<anonymous> (/Users/francis/workspace/mingo/test/test.js:41:10)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
*/

Test 1 does not pass all equality checks
Test 2 throws an exception

Tested with Mingo@v0.8.

@kofrasa kofrasa added the bug label Dec 1, 2016
@kofrasa kofrasa changed the title Incorrect matching of deeply nested values without array index in selectors Incorrect matching of deeply nested values in arrays Dec 2, 2016
@kofrasa kofrasa changed the title Incorrect matching of deeply nested values in arrays Incorrect matching of deeply nested values and whole objects Dec 3, 2016
kofrasa added a commit that referenced this issue Dec 8, 2016
MongoDB permits traversing a single level of nesting for
values in an array for non-numeric selector key.
@kofrasa
Copy link
Owner Author

kofrasa commented Dec 12, 2016

Fixed in 0.8.1

@kofrasa kofrasa closed this as completed Dec 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant