[SERVER-6135] Positional operator in projection shouldn't match embedded document (only array) Created: 19/Jun/12  Updated: 11/Nov/19  Resolved: 11/Nov/19

Status: Closed
Project: Core Server
Component/s: Querying
Affects Version/s: 2.1.2, 2.6.3
Fix Version/s: None

Type: Bug Priority: Minor - P4
Reporter: Ben Becker Assignee: Ian Boros
Resolution: Won't Fix Votes: 1
Labels: query-44-grooming
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Operating System: ALL
Sprint: Query 2019-11-04, Query 2019-11-18
Participants:

 Description   

The following projection operation should likely throw a user assertion (or return nothing) due to matching an embedded object instead of the intended array:

> db.a.save( { a:{b:1} } )
> db.a.find( { a:{b:1} }, { 'a.$':1 } )
{ "_id" : ObjectId("4fe0f094026e93e0aaef076d"), "a" : { } }



 Comments   
Comment by David Storch [ 11/Nov/19 ]

I agree. Let's close this as Won't Fix and make sure this change is documented.

Comment by Ian Boros [ 06/Nov/19 ]

For the sub-object case:

db.c.insert({a: {b: 1}})
db.c.find({"a.b": 1}, {'a.$': 1}).toArray();

Which in 4.2 returned

[ { "_id" : ObjectId("5dc32e5dc382818df1a29263"), "a" : { } } ]

We'd take this path in projectionExec.

...
    } else if (elt.type() == Object) {
        BSONObjBuilder subBob;
        BSONObjIterator it(elt.embeddedObject());
        while (it.more()) {
            subfm.append(&subBob, it.next(), details, arrayOpType).transitional_ignore();
        }
        bob->append(elt.fieldName(), subBob.obj());
    } else {
...

When the element being appended was the 'b' field of 'a' subBob would be empty, so we'd end up appending an empty field. This feels like a bug. Whether it should have appended nothing or just left the field as-is is a separate question, but I think both are reasonable, and would like to leave the current 4.3 behavior (leaving the field as is).

For the case where 'a' is not an array, 4.2 is not even consistent between cases where a top-level field is being projected and a sub-field is being projected. Consider:

> db.c.insert({a: "astring"})
> db.c.find({"a": "astring"}, {'a.$': 1})
{ "_id" : ObjectId("5dc33418a2e1d48385a60bec") } // 'a' is missing entirely

> db.c.insert({a: {b: "astring"}})
> db.c.find({"a.b": "astring"}, {'a.b.$': 1})
{ "_id" : ObjectId("5dc3343ca2e1d48385a60bed"), "a" : {  } } // We include an empty 'a' sub-object.

This whole feels like a bug to me. In 4.3 the behavior is more consistent.

> db.c.insert({a: "astring"})
WriteResult({ "nInserted" : 1 })
> db.c.find({"a": "astring"}, {'a.$': 1})
{ "_id" : ObjectId("5dc3372ecf7239995f220ee3"), "a" : "astring" } // 'a' is included entirely.

> db.c.insert({a: {b: "astring"}})
WriteResult({ "nInserted" : 1 })
> db.c.find({"a.b": "astring"}, {'a.b.$': 1})
{ "_id" : ObjectId("5dc336e6cf7239995f220ee1"), "a" : { "b" : "astring" } } // a.b' is included entirely.

I'd also just like to leave the behavior as-is here.

david.storch If you agree with this, then I will close as "Won't Fix" and update the design doc.

Comment by David Storch [ 05/Jul/19 ]

I'm flagging for re-triage, as this is relevant to work we're doing to clean up the internal implementation of positional projection.

CC ian.boros anton.korshunov

Generated at Thu Feb 08 03:10:50 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.