Skip to content

Commit 5f6ff62

Browse files
authored
MONGOID-5037 use $pull instead of $pullAll for when documents change before destroying all (#5341)
* MONGOID-5037 use $pull instead of $pullAll for when documents change before destroying all * MONGOID-5037 unpend test * MONGOID-5037 sometimes use $pull sometimes use $pullAll * MONGOID-5037 fix spacing * MONGOID-5037 check base persisted before doing queries * Update lib/mongoid/association/embedded/batchable.rb * MONGOID-5037 remov extra check
1 parent 449022f commit 5f6ff62

File tree

4 files changed

+117
-7
lines changed

4 files changed

+117
-7
lines changed

lib/mongoid/association/embedded/batchable.rb

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,38 @@ def batch_clear(docs)
5050
_unscoped.clear
5151
end
5252

53-
# Batch remove the provided documents as a $pullAll.
53+
# Batch remove the provided documents as a $pullAll or $pull.
5454
#
5555
# @example Batch remove the documents.
5656
# batchable.batch_remove([ doc_one, doc_two ])
5757
#
5858
# @param [ Array<Document> ] docs The docs to remove.
5959
# @param [ Symbol ] method Delete or destroy.
6060
def batch_remove(docs, method = :delete)
61+
# If the _id is nil, we cannot use $pull and delete by searching for
62+
# the id. Therefore we have to use pullAll with the documents'
63+
# attributes.
6164
removals = pre_process_batch_remove(docs, method)
65+
pulls, pull_alls = removals.partition { |o| !o["_id"].nil? }
66+
67+
if !_base.persisted?
68+
post_process_batch_remove(docs, method) unless docs.empty?
69+
return reindex
70+
end
71+
6272
if !docs.empty?
63-
collection.find(selector).update_one(
64-
positionally(selector, "$pullAll" => { path => removals }),
65-
session: _session
66-
)
73+
if !pulls.empty?
74+
collection.find(selector).update_one(
75+
positionally(selector, "$pull" => { path => { "_id" => { "$in" => pulls.pluck("_id") } } }),
76+
session: _session
77+
)
78+
end
79+
if !pull_alls.empty?
80+
collection.find(selector).update_one(
81+
positionally(selector, "$pullAll" => { path => pull_alls }),
82+
session: _session
83+
)
84+
end
6785
post_process_batch_remove(docs, method)
6886
else
6987
collection.find(selector).update_one(

spec/integration/associations/embeds_many_spec.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,6 @@
172172
# Mongoid uses the new value of `x` in the $pullAll query,
173173
# which doesn't match the document that is in the database,
174174
# resulting in the empty array assignment not taking effect.
175-
pending 'MONGOID-5037'
176-
177175
canvas.shapes.first.x = 1
178176
canvas.shapes = []
179177
canvas.save!

spec/mongoid/association/embedded/embeds_many/proxy_spec.rb

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,6 +2210,79 @@ class TrackingIdValidationHistory
22102210
end
22112211
end
22122212
end
2213+
2214+
context "when modifying the document beforehand" do
2215+
let(:parent) { EmmParent.new }
2216+
2217+
before do
2218+
2219+
parent.blocks << EmmBlock.new(name: 'test', children: [size: 1, order: 1])
2220+
parent.save!
2221+
2222+
parent.blocks[0].children[0].assign_attributes(size: 2)
2223+
2224+
parent.blocks.destroy_all(:name => 'test')
2225+
end
2226+
2227+
it "deletes the correct document in the database" do
2228+
expect(parent.reload.blocks.length).to eq(0)
2229+
end
2230+
end
2231+
2232+
context "when nil _id" do
2233+
let(:parent) { EmmParent.new }
2234+
2235+
before do
2236+
parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2237+
parent.blocks << EmmBlock.new(_id: nil, name: 'test2', children: [size: 1, order: 1])
2238+
parent.save!
2239+
2240+
parent.blocks.destroy_all(:name => 'test')
2241+
end
2242+
2243+
it "deletes only the matching documents in the database" do
2244+
expect(parent.reload.blocks.length).to eq(1)
2245+
end
2246+
end
2247+
2248+
# Since without an _id field we must us a $pullAll with the attributes of
2249+
# the embedded document, if you modify it beforehand, the query will not
2250+
# be able to find the correct document to pull.
2251+
context "when modifying the document with nil _id" do
2252+
let(:parent) { EmmParent.new }
2253+
2254+
before do
2255+
parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2256+
parent.blocks << EmmBlock.new(_id: nil, name: 'test2', children: [size: 1, order: 1])
2257+
parent.save!
2258+
2259+
parent.blocks[0].children[0].assign_attributes(size: 2)
2260+
2261+
parent.blocks.destroy_all(:name => 'test')
2262+
end
2263+
2264+
it "does not delete the correct documents" do
2265+
expect(parent.reload.blocks.length).to eq(2)
2266+
end
2267+
end
2268+
2269+
context "when documents with and without _id" do
2270+
let(:parent) { EmmParent.new }
2271+
2272+
before do
2273+
parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2274+
parent.blocks << EmmBlock.new(name: 'test', children: [size: 1, order: 1])
2275+
parent.save!
2276+
2277+
parent.blocks[1].children[0].assign_attributes(size: 2)
2278+
2279+
parent.blocks.destroy_all(:name => 'test')
2280+
end
2281+
2282+
it "does not delete the correct documents" do
2283+
expect(parent.reload.blocks.length).to eq(0)
2284+
end
2285+
end
22132286
end
22142287
end
22152288

spec/mongoid/association/embedded/embeds_many_models.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,24 @@ class EmmStudent
203203

204204
embedded_in :school, class_name: "EmmSchool"
205205
end
206+
207+
class EmmParent
208+
include Mongoid::Document
209+
embeds_many :blocks, class_name: "EmmBlock"
210+
end
211+
212+
class EmmBlock
213+
include Mongoid::Document
214+
field :name, type: String
215+
embeds_many :children, class_name: "EmmChild"
216+
end
217+
218+
class EmmChild
219+
include Mongoid::Document
220+
embedded_in :block, class_name: "EmmBlock"
221+
222+
field :size, type: Integer
223+
field :order, type: Integer
224+
field :t
225+
end
226+

0 commit comments

Comments
 (0)