-
Type: Bug
-
Resolution: Duplicate
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Aggregation Framework
-
None
-
Query
-
Fully Compatible
-
ALL
If you use a non-inclusion dotted field during a $project stage, you can get different results depending on if the incoming document contains anything in that path:
> db.foo.drop() true > db.foo.insert({a: [{b: 1}, {b: 2}]}) WriteResult({ "nInserted" : 1 }) > db.foo.aggregate([{$project: {"x.y": {$literal: 1}}}]) // "x.y" didn't exist, so we created a nested field. { "_id" : ObjectId("56fae6c03ef38a5ce210b232"), "x" : { "y" : 1 } } > db.foo.aggregate([{$project: {"a.b": {$literal: 1}, c: "$a.b"}}]) // "a.b" did exist, so we modified each value of "a.b" to be 1. { "_id" : ObjectId("56fae6c03ef38a5ce210b232"), "a" : [ { "b" : 1 }, { "b" : 1 } ], "c" : [ 1, 2 ] }
What's even weirder is this behavior:
> db.foo.find() { "_id" : ObjectId("56fae6c03ef38a5ce210b232"), "a" : [ { "b" : 1 }, { "b" : 2 } ] } > db.foo.aggregate([{$project: {"a.b": {$literal: 1}}}]) // We created a nested field "a.b", even though there was previously a different structure in "a.b". { "_id" : ObjectId("56fae6c03ef38a5ce210b232"), "a" : { "b" : 1 } }
Here the document did have something in "a.b", but nothing else was using it, so it was projected out, hence the different behavior from the example above, which specified {c: "$a.b"} so that the field "a.b" was needed, and hence remained in the incoming document.
> db.foo.explain().aggregate([{$project: {"a.b": {$literal: 1}}}]) { "waitedMS" : NumberLong(0), "stages" : [ { "$cursor" : { "query" : { }, "fields" : { "_id" : 1 }, ...
> db.foo.explain().aggregate([{$project: {"a.b": {$literal: 1}, c: "$a.b"}}]) { "waitedMS" : NumberLong(0), "stages" : [ { "$cursor" : { "query" : { }, "fields" : { "a.b" : 1, "_id" : 1 }, ...
- duplicates
-
SERVER-18966 Allow exclusion in $project stage of aggregation pipeline
- Closed
- is related to
-
SERVER-18966 Allow exclusion in $project stage of aggregation pipeline
- Closed