[SERVER-6864] positional operator projection inclusion can mess up array based non positional operator Created: 27/Aug/12  Updated: 04/Nov/19  Resolved: 04/Nov/19

Status: Closed
Project: Core Server
Component/s: Querying
Affects Version/s: None
Fix Version/s: 4.3.1

Type: Bug Priority: Major - P3
Reporter: Aaron Staple Assignee: Ian Boros
Resolution: Done Votes: 2
Labels: query-44-grooming, query_triage
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: File server6864.js    
Issue Links:
Depends
Duplicate
is duplicated by SERVER-5247 Support updating more than one array ... Closed
Related
related to SERVER-831 Positional Operator Matching Nested A... Closed
related to SERVER-6866 Support dotted field past positional ... Backlog
related to SERVER-6399 Refactor update() code Closed
is related to SERVER-15164 positional operator element mismatch ... Closed
Backwards Compatibility: Fully Compatible
Operating System: ALL
Sprint: Query 2019-11-04, Query 2019-11-18
Participants:
Case:

 Description   

A $slice and a positional inclusion on different fields do not work correctly together:

c.save( { a:[ 1, 2, 3 ], z:[ 11, 12, 13 ] } );
 
// The first two elements of 'a' are returned.
printjson( c.find( { z:13 }, { a:{ $slice:2 } } ).toArray() );
 
// The third element of 'a' is returned (incorrectly), because the third element of 'z' is matched.
printjson( c.find( { z:13 }, { a:{ $slice:2 }, 'z.$':1 } ).toArray() );

There's also a case where projecting a field of a subobject nested within an array works incorrectly if a positional projection is used on another field. Array field selection should be limited to inclusion fields with a positional operator.

> c.save( { a:[ { b:1, c:2 }, { b:3, c:4 } ], z:[ 11, 12, 13 ] } )
 
// Expected projection for a.b:1.
> c.find( { z:12 }, { 'a.b':1 } )
{ "_id" : ObjectId("503aeb6760273eae2b9d57f7"), "a" : [ { "b" : 1 }, { "b" : 3 } ] }
 
// In this case, the positional match is applied to the 'a' array as well as the 'z' array.
> c.find( { z:12 }, { 'a.b':1, 'z.$':1 } )
{ "_id" : ObjectId("503aeb6760273eae2b9d57f7"), "a" : [ { "b" : 3, "c" : 4 } ], "z" : [ 12 ] }
 
// In this case, the query matched 'z' index 2, which does not exist in the 'a' array, and an error is triggered.
> c.find( { z:13 }, { 'a.b':1, 'z.$':1 } )
error: { "$err" : "positional operator element mismatch", "code" : 16353 }

There are other cases where a nested inclusion may conflict with a positional inclusion. In cases like that we should probably uassert:

> c.save( { a:[ { b:1, c:2 }, { b:3, c:4 } ] } )
> c.find( { 'a.b':3 }, { 'a.b':1 } )
{ "_id" : ObjectId("503af2d560273eae2b9d57f9"), "a" : [ { "b" : 1 }, { "b" : 3 } ] }
 
// In this case the a.$ currently supersedes the a.b.  But we might want to uassert instead.
> c.find( { 'a.b':3 }, { 'a.b':1, 'a.$':1 } )
{ "_id" : ObjectId("503af2d560273eae2b9d57f9"), "a" : [ { "b" : 3, "c" : 4 } ] }



 Comments   
Comment by Githook User [ 01/Nov/19 ]

Author:

{'username': 'puppyofkosh', 'email': 'ian.boros@mongodb.com', 'name': 'Ian Boros'}

Message: SERVER-6864 test that positional operator is compatible with documents that have multiple arrays
Branch: master
https://github.com/mongodb/mongo/commit/fbb940bd7f9193f508f7d2dbb4286113eaffe78e

Comment by Ian Boros [ 28/Oct/19 ]

I believe much of this will be fixed "for free" by the unification of the projection implementations.

Comment by David Storch [ 05/Jul/19 ]

Flagging for re-triage given the work that the Query Team is planning around cleaning up the implementation of $slice and positional projection.

CC ian.boros anton.korshunov@mongodb.com

Comment by Asya Kamsky [ 19/Apr/16 ]

Both of examples jesse gave now properly give the same error ("Executor error during find command: InternalError: ambiguous positional projection").

Original examples still give incorrect results, though.

Comment by A. Jesse Jiryu Davis [ 04/Apr/13 ]

> c.insert({"_id": 1, "a" : [1, 2], "b" : [ { "x" : 1 } ] })
> c.find({'a': 2, 'b': {$elemMatch: {x: 1}}}, {'b.$': true})
{ "_id" : 1, "a" : [ 1, 2 ], "b" : [ { "x" : 1 } ] }
> c.find({'b': {$elemMatch: {x: 1}}, 'a': 2}, {'b.$': true})
error: { "$err" : "positional operator element mismatch", "code" : 16353 }

So the meaning of $ depends on the order of fields in the query. b.$ should, of course, mean "the position of the element matched in b", but it actually means, "the position of the element matched in the last array mentioned in the query." Which is b in the first find and a in the second find. In the second case, $ is 2, but b has only 1 element, so we get an error.

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