-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
None
-
Affects Version/s: 3.1.6, 4.0.0 final, 5.1.1
-
Component/s: None
-
Labels:None
-
Environment:Ubuntu/OSX, Ruby 2.0 - 2.3
I'm having this issue after updating from MongoDB 2.4 to 2.6. I'm still running Mongoid 3.1 in this project however after extensive testing this issue still seems to be relevant all the way through Mongoid 5 (haven't tested 6). Its related to the positionally method when updating deeply embedded documents.
From the MongoDB documentation https://docs.mongodb.com/manual/reference/operator/update/positional/
Remember that the positional $ operator acts as a placeholder for the first match of the update query document.
Given the following atomic selector (of an embedded document nested within another embedded):
{"_id"=>"576ad5a2eea25fa26f000001", "items._id"=>"576ad5a2eea25fa26f000002", "items.0.items._id"=>"576ad5a3eea25fa26f000004"}
And given the following updates:
{"$set"=>{"items.0.items.1.name"=>"c"}}
The following line within positionally
keys = keys.sort_by { |s| s.length*-1 }
Will cause the most specific index to be positionally updated. Resulting in the following:
{"$set"=>{"items.0.items.$.name"=>"c"}}
However this is not the first element, this is the 2nd element being updated, which violates the MongoDB requirement. Instead if switching to:
keys = keys.sort_by { |s| s.length }
will result in the expected result of
{"$set"=>{"items.$.items.1.name"=>"c"}
Repo steps
require 'spec_helper' class BasicParent include Mongoid::Document field :name embeds_many :items, class_name: 'BasicChild' end class BasicChild include Mongoid::Document embedded_in :basic field :name embeds_many :items, class_name: 'BasicSubChild' end class BasicSubChild include Mongoid::Document embedded_in :basic field :name end describe BasicParent do let(:parent) { BasicParent.create(name: 'a') } let(:child) { parent.items.create(name: 'a') } let!(:nested_a) { child.items.create(name: 'a') } let!(:nested_b) { child.items.create(name: 'b') } # this spec fails in multiple projects of mine across many versions. One # project does work (Mongoid 5.1.2) however it works only becuase for # some reason it doesnt update any position with $ it 'should properly support updating nested items' do nested_b.name = 'c' nested_b.save child.reload expect(child.items.map(&:name)).to eq ['a', 'c'] end it 'should properly support updating nested items via parent' do nested_b.name = 'c' child.save child.reload expect(child.items.map(&:name)).to eq ['a', 'c'] end end
I can monkey patch but please help me understand the ramifications of this change and if it will have other consequences. There clearly was an intention behind sorting the keys by most specific first.