mongomock icon indicating copy to clipboard operation
mongomock copied to clipboard

Positional $ update_one doesn't update different object levels correctly

Open Yergidy opened this issue 3 years ago • 0 comments

When using the positional $ operator to update multiple properties in an array of nested objects if you supply different levels of object nesting it will only take the first level specified and applies it to all properties. Pymongo on an actual db correctly updates the object.

For example: For an original object of:

{'a_list': [{'outer_bool': False, 'outer_str': 'blah', 'inner': {'inner_bool': False, 'inner_str': 'blee'}}], '_id': ObjectId(<id>)}

With the following update_one call:

        the_collection.update_one({"_id": ObjectId(<id>), "a_list.outer_str": "blah"},
                        {"$set": {"a_list.$.outer_bool": True, "a_list.$.outer_string": "blah_update",
                                    "a_list.$.inner.inner_bool": True, "a_list.$.inner.inner_str": "blee_update"}})

Returns the following in mongomock:

{'a_list': [{'outer_bool': True, 'outer_str': 'blah_update', 'inner': {'inner_bool': False, 'inner_str': 'blee'}, 'inner_bool': True, 'inner_str': 'blee_update'}], '_id': ObjectId(<id>)}

And the following in pymongo:

{'_id': ObjectId(<id>), 'a_list': [{'outer_bool': True, 'outer_str': 'blah_update', 'inner': {'inner_bool': True, 'inner_str': 'blee_update'}}]}

As a workaround you can separate out the updates by level:

    the_collection.update_one({"_id": ObjectId<id>), "a_list.outer_str": "blah"},
                    {"$set": {"a_list.$.inner.inner_bool": True, "a_list.$.inner.inner_str": "blee_update"}})
    the_collection.update_one({"_id": ObjectId<id>), "a_list.outer_str": "blah"},
                    {"$set": {"a_list.$.outer_bool": True, "a_list.$.outer_str": "blah_update"}})

Yergidy avatar Jul 12 '22 19:07 Yergidy