-
Type: Improvement
-
Resolution: Unresolved
-
Priority: Minor - P4
-
None
-
Affects Version/s: 7.0.4
-
Component/s: Associations, Persistence
In MongoDB 3.6, filtered positional update operator was added as described here: https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#update-nested-arrays-in-conjunction-with. This operator permits find-and-modify operations on nested arrays of embedded documents - specifically, it is free of the restriction of the positional update operator (https://docs.mongodb.com/manual/reference/operator/update/positional/) which only works with one level of nested arrays.
Mongoid should use the filtered positional update operator to solve the following reported problem:
This seems to have been fixed before but it doesn't use the positional operator when an embedded document has embedded documents.
require 'mongoid' Mongoid.connect_to 'embedded_positional_operators_test' class Team include Mongoid::Document embeds_many :players field :name, type: String, default: '' end class Player include Mongoid::Document embeds_many :previous_teams embedded_in :team, inverse_of: :players field :name, type: String, default: '' end class PreviousTeam include Mongoid::Document embedded_in :player, inverse_of: :previous_teams field :name, type: String, default: '' field :year, type: String, default: '' end Team.delete_all Team.create!(name: 'Falcons') falcons_instance_1 = Team.first falcons_instance_2 = Team.first falcons_instance_1.players.create!(name: 'Vidur', previous_teams: [{name: 'Eagles', year: '2018'}]) falcons_instance_2.players.create!(name: 'Jonathon', previous_teams: [{name: 'Paaaaaanthers', year: '2018'}]) me = falcons_instance_2.players.find_by(name: 'Jonathon') # me.previous_teams.find_or_initialize_by(year: '2018').update(name: 'Panthers') me.previous_teams.find_or_initialize_by(year: '2018').assign_attributes(name: 'Panthers') me.save Team.first.players.each do |player| previous_teams = player.previous_teams.each.map(&:name).join(', ') puts "Player Name: #{player.name}, Previous Teams: #{previous_teams}" end
So the expected print would be:
Player Name: Vidur, Previous Teams: Eagles
Player Name: Jonathon, Previous Teams: Panthers
but it returns:
Player Name: Vidur, Previous Teams: Panthers
Player Name: Jonathon, Previous Teams: Paaaaaanthers
it looks like the query being created is:
{ q: { _id: ObjectId('5db0a55728f9d506e57a336d'), players._id: ObjectId('5db0a55728f9d506e57a3370') }, u: { $set: { players.0.previous_teams.0.name: "Panthers" } }
And that first 0 should be the positional operator $.
I looked through the code and found it was being done here and in there I see it uses positional operator only when nesting 1 level deep. Looking at the commit that added that im guessing its needed when the embedded document with the same name?
- related to
-
MONGOID-4172 Regression: positional operators not used to update embedded records
- Closed