[SERVER-53284] Unexpected update with pipeline result of embedded doc Created: 08/Dec/20 Updated: 27/Oct/23 Resolved: 02/Feb/21 |
|
| Status: | Closed |
| Project: | Core Server |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Major - P3 |
| Reporter: | Mikhail Ilchenko | Assignee: | Charlie Swanson |
| Resolution: | Works as Designed | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Environment: |
$ mongo --version |
||
| Sprint: | Query 2021-02-08 |
| Participants: |
| Description |
|
I have a doc in my collection which was inserted
If I update it with
I get {'obj': {'a': 1, 'b': 2, 'c': 3}} (same as doc update, as expected) But if I update it with pipeline
I get {'obj': {'a': 1, 'c': 3, 'b': 2}} (like there are not set of obj, but set of non exist b in obj) If I need to update field of embedded doc, I use update with dot notation. But this full embedded doc update has unexpected behavior, therefore I created bug. Also I chose Python Driver project because I found it with pymongo and motor, but It can be mongo server problem. If it is, move it please. |
| Comments |
| Comment by Charlie Swanson [ 02/Feb/21 ] | ||||||||||||||||
|
Hi all, I have taken a look at the issue and while it is indeed confusing, everything is behaving as it is expected to in this scenario. The aggregation stages $set, $addFields, and $project all have a syntax which permits two ways to specify the same thing: dotted paths or sub-objects. This decision predates me, but I would venture a guess that we permit both syntaxes because the dotted paths are shorter when you need to change one thing, but if you change many fields within a sub-object, it becomes redundant. Taking your example, both of these mean the same thing in $set, $addFields, or $project:
In fact, the code will parse these two things into the same abstract syntax tree and execution structures. I realize this is confusing. As a workaround, I believe you can still get what you want by using the "$literal" operator:
| ||||||||||||||||
| Comment by Eric Sedor [ 05/Jan/21 ] | ||||||||||||||||
|
Hi mix.ilchenko@gmail.com, building on what shane.harvey has said, you can replace the value of obj using the "Update document" style update as described in the update parameter documentation.
In the aggregation pipeline style, the following two operations seem equivalent:
I am looking into whether or not we intend to support subdocument replacement in pipeline updates, and will assign this ticket to an appropriate team. | ||||||||||||||||
| Comment by Mikhail Ilchenko [ 09/Dec/20 ] | ||||||||||||||||
|
Sorry, that I didn't write my python version, it is 3.8. You are right that this problem is not because of ordering and bson won't help. Your two questions are good formulated for this task. There can be "No" answer for the first one, and if so I'm interested in answer for the second question. Thank you and waiting for server team respond | ||||||||||||||||
| Comment by Shane Harvey [ 08/Dec/20 ] | ||||||||||||||||
|
mix.ilchenko@gmail.com I've moved this ticket from PYTHON to SERVER. I think the key question is: Is the aggregation pipeline $set operator supposed to work the same as the update $set operator? The other question is: is it possible to mimic the behavior of the update $set operator via a pipeline update? I'll let the server team respond. | ||||||||||||||||
| Comment by Shane Harvey [ 08/Dec/20 ] | ||||||||||||||||
|
I can reproduce this behavior even on Python 3.7+ so this appears to be a server issue:
| ||||||||||||||||
| Comment by Shane Harvey [ 08/Dec/20 ] | ||||||||||||||||
|
Hi mix.ilchenko@gmail.com, what version of python are you using? If you are using Python < 3.7 then you need to use an ordered dictionary type such as bson.son.SON or OrderedDict because python dictionaries we unordered before that. See:
|