-
Type: Bug
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: Persistence
-
None
-
Fully Compatible
Given the following setup:
- Truck embeds many crates
- Crate embeds many toys
- There is a truck with one crate
If we attempt to perform the following three operations on the truck in question:
- change the attribute of the crate
- add a toy to the crate
- add another crate
... then Mongoid fails to save the resulting truck.
let!(:truck) { Truck.create! }
let!(:crates) { truck.crates.create!(volume: 1) }
...
truck.crates.first.volume = 2
truck.crates.first.toys.build(name: 'Bear')
truck.crates.build
truck.save!
While processing the save, the following updates and conflicts are generated:
[132, 141] in /home/w/apps/mongoid/lib/mongoid/persistable/updatable.rb 132: # @since 1.0.0 133: def update_document(options = {}) 134: prepare_update(options) do 135: updates, conflicts = init_atomic_updates 136: byebug => 137: unless updates.empty? 138: coll = collection(_root) 139: selector = atomic_selector 140: coll.find(selector).update_one(positionally(selector, updates), session: _session) 141: conflicts.each_pair do |key, value| (byebug) updates {"$set"=>{"crates.0.volume"=>2}} (byebug) conflicts {"$push"=>{"crates.0.toys"=>{"$each"=>[{"_id"=>BSON::ObjectId('5f4bda5f2c97a61e2d76a7f9'), "name"=>"Bear"}]}, "crates"=>{"$each"=>[{"_id"=>BSON::ObjectId('5f4bda5c2c97a61e2d76a7f8')}]}}}
So, what is happening here is Mongoid will perform one update of the crate attribute and then attempt to add a toy and add a crate together in the next write.
Server fails the latter operation with:
> Updating the path 'crates' would create a conflict at 'crates' (40) (on localhost:14440, modern retry, attempt 1)
This problem is easier to encounter when timestamps and callback cascades are enabled, in which case Mongoid internally performs the timestamp updates on the embedded documents. To encounter this issue, then, the application only needs to add a top-level association and add a nested association to an existing top-level association member in the same save call (provided the top-level association cascades callbacks and the nested model has timestamps enabled).
- is duplicated by
-
MONGOID-4957 Bad conflicts key for atomic_updates when deeply nested structure
- Closed
- is related to
-
MONGOID-5026 Coalesce updates where possible
- Closed
- links to