Module: Mongoid::Association::Embedded::Batchable
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Included In:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
::Mongoid::Positional
|
|
Defined in: | lib/mongoid/association/embedded/batchable.rb |
Overview
Contains behavior for executing operations in batch on embedded documents.
Instance Attribute Summary
-
#insertable? ⇒ true | false
readonly
private
Internal use only
Internal use only
Are we in a state to be able to batch insert?
-
#inserts_valid ⇒ true | false
rw
private
Internal use only
Internal use only
Are the inserts currently valid?
-
#inserts_valid=(value) ⇒ true | false
rw
private
Internal use only
Internal use only
::Set
the inserts valid flag. -
#path ⇒ String
rw
private
Internal use only
Internal use only
Get the atomic path.
-
#path=(value) ⇒ String
rw
private
Internal use only
Internal use only
::Set
the atomic path.
Instance Method Summary
-
#batch_clear(docs) ⇒ Array
Clear all of the docs out of the association in a single swipe.
-
#batch_insert(docs) ⇒ Array<Hash>
Insert new documents as a batch push ($push with $each).
-
#batch_remove(docs, method = :delete)
Batch remove the provided documents as a $pullAll or $pull.
-
#batch_replace(docs) ⇒ Array<Hash>
Batch replace the provided documents as a $set.
-
#add_atomic_sets(sets)
private
Internal use only
Internal use only
Add the atomic sets to the base document.
-
#clear_atomic_path_cache
private
Internal use only
Internal use only
Clear the cache for path and atomic_paths.
-
#execute_batch_push(docs) ⇒ Array<Hash>
private
Internal use only
Internal use only
Perform a batch persist of the provided documents with $push and $each.
-
#execute_batch_set(docs) ⇒ Array<Hash>
private
Internal use only
Internal use only
Perform a batch persist of the provided documents with a $set.
-
#normalize_docs(docs) ⇒ Array<Document>
private
Internal use only
Internal use only
Normalize the documents, in case they were provided as an array of hashes.
-
#post_process_batch_insert(docs) ⇒ Enumerable
private
Internal use only
Internal use only
Post process the documents after batch insert.
-
#post_process_batch_remove(docs, method) ⇒ Array<Document>
private
Internal use only
Internal use only
Post process the batch removal.
-
#pre_process_batch_insert(docs) ⇒ Array<Hash>
private
Internal use only
Internal use only
Pre processes the batch insert for the provided documents.
-
#pre_process_batch_remove(docs, method) ⇒ Array<Hash>
private
Internal use only
Internal use only
Pre process the batch removal.
-
#selector ⇒ Hash
private
Internal use only
Internal use only
Get the selector for executing atomic operations on the collection.
::Mongoid::Positional
- Included
#positionally | Takes the provided selector and atomic operations and replaces the indexes of the embedded documents with the positional operator when needed. |
#process_operations, #process_updates, #replace_index |
Instance Attribute Details
#insertable? ⇒ true
| false
(readonly, private)
Are we in a state to be able to batch insert?
# File 'lib/mongoid/association/embedded/batchable.rb', line 199
def insertable? persistable? && !_assigning? && inserts_valid end
#inserts_valid ⇒ true
| false
(rw, private)
Are the inserts currently valid?
# File 'lib/mongoid/association/embedded/batchable.rb', line 211
def inserts_valid @inserts_valid end
#inserts_valid=(value) ⇒ true
| false
(rw, private)
::Set
the inserts valid flag.
# File 'lib/mongoid/association/embedded/batchable.rb', line 225
def inserts_valid=(value) @inserts_valid = value end
#path ⇒ String (rw, private)
Get the atomic path.
# File 'lib/mongoid/association/embedded/batchable.rb', line 260
def path @path ||= if _unscoped.empty? Mongoid::Atomic::Paths::Embedded::Many.position_without_document(_base, _association) else _unscoped.first.atomic_path end end
#path=(value) ⇒ String (rw, private)
::Set
the atomic path.
# File 'lib/mongoid/association/embedded/batchable.rb', line 289
def path=(value) @path = value end
Instance Method Details
#add_atomic_sets(sets) (private)
Add the atomic sets to the base document.
#batch_clear(docs) ⇒ Array
Clear all of the docs out of the association in a single swipe.
# File 'lib/mongoid/association/embedded/batchable.rb', line 35
def batch_clear(docs) pre_process_batch_remove(docs, :delete) unless docs.empty? collection.find(selector).update_one( positionally(selector, "$unset" => { path => true }), session: _session ) # This solves the case in which a user sets, clears and resets an # embedded document. Previously, since the embedded document was # already marked not a "new_record", it wouldn't be persisted to # the second time. This change fixes that and allows it to be persisted. docs.each { |doc| doc.new_record = true } post_process_batch_remove(docs, :delete) end _unscoped.clear end
#batch_insert(docs) ⇒ Array<Hash>
Insert new documents as a batch push ($push with $each). This ensures that all callbacks are run at the appropriate time and only 1 request is made to the database.
# File 'lib/mongoid/association/embedded/batchable.rb', line 23
def batch_insert(docs) execute_batch_push(docs) end
#batch_remove(docs, method = :delete)
Batch remove the provided documents as a $pullAll or $pull.
# File 'lib/mongoid/association/embedded/batchable.rb', line 59
def batch_remove(docs, method = :delete) # If the _id is nil, we cannot use $pull and delete by searching for # the id. Therefore we have to use pullAll with the documents' # attributes. removals = pre_process_batch_remove(docs, method) pulls, pull_alls = removals.partition { |o| !o["_id"].nil? } if !_base.persisted? post_process_batch_remove(docs, method) unless docs.empty? return reindex end if !docs.empty? if !pulls.empty? collection.find(selector).update_one( positionally(selector, "$pull" => { path => { "_id" => { "$in" => pulls.pluck("_id") } } }), session: _session ) end if !pull_alls.empty? collection.find(selector).update_one( positionally(selector, "$pullAll" => { path => pull_alls }), session: _session ) end post_process_batch_remove(docs, method) else collection.find(selector).update_one( positionally(selector, "$set" => { path => [] }), session: _session ) end reindex end
#batch_replace(docs) ⇒ Array<Hash>
Batch replace the provided documents as a $set.
# File 'lib/mongoid/association/embedded/batchable.rb', line 102
def batch_replace(docs) if docs.blank? if _assigning? && !empty? _base.delayed_atomic_sets.delete(path) clear_atomic_path_cache _base.add_atomic_unset(first) target_duplicate = _target.dup pre_process_batch_remove(target_duplicate, :delete) post_process_batch_remove(target_duplicate, :delete) else batch_remove(_target.dup) end elsif _target != docs _base.delayed_atomic_sets.delete(path) unless _assigning? docs = normalize_docs(docs).compact _target.clear and _unscoped.clear _base.delayed_atomic_unsets.delete(path) clear_atomic_path_cache inserts = execute_batch_set(docs) add_atomic_sets(inserts) end end
#clear_atomic_path_cache (private)
Clear the cache for path and atomic_paths. This method is used when the path method is used, and the association has not been set on the document yet, which can cause path and atomic_paths to be calculated incorrectly later.
# File 'lib/mongoid/association/embedded/batchable.rb', line 274
def clear_atomic_path_cache self.path = nil _base.instance_variable_set("@atomic_paths", nil) end
#execute_batch_push(docs) ⇒ Array<Hash> (private)
Perform a batch persist of the provided documents with $push and $each.
# File 'lib/mongoid/association/embedded/batchable.rb', line 178
def execute_batch_push(docs) self.inserts_valid = true pushes = pre_process_batch_insert(docs) if insertable? collection.find(selector).update_one( positionally(selector, '$push' => { path => { '$each' => pushes } }), session: _session ) post_process_batch_insert(docs) end pushes end
#execute_batch_set(docs) ⇒ Array<Hash> (private)
Perform a batch persist of the provided documents with a $set.
# File 'lib/mongoid/association/embedded/batchable.rb', line 155
def execute_batch_set(docs) self.inserts_valid = true inserts = pre_process_batch_insert(docs) if insertable? collection.find(selector).update_one( positionally(selector, '$set' => { path => inserts }), session: _session ) post_process_batch_insert(docs) end inserts end
#normalize_docs(docs) ⇒ Array<Document> (private)
Normalize the documents, in case they were provided as an array of hashes.
# File 'lib/mongoid/association/embedded/batchable.rb', line 240
def normalize_docs(docs) if docs.first.is_a?(::Hash) docs.map do |doc| attributes = { _association: _association, _parent: _base } attributes.merge!(doc) Factory.build(klass, attributes) end else docs end end
#post_process_batch_insert(docs) ⇒ Enumerable
(private)
Post process the documents after batch insert.
# File 'lib/mongoid/association/embedded/batchable.rb', line 368
def post_process_batch_insert(docs) docs.each do |doc| doc.new_record = false doc.run_after_callbacks(:create, :save) doc.post_persist end end
#post_process_batch_remove(docs, method) ⇒ Array<Document> (private)
Post process the batch removal.
# File 'lib/mongoid/association/embedded/batchable.rb', line 387
def post_process_batch_remove(docs, method) docs.each do |doc| doc.run_after_callbacks(:destroy) if method == :destroy doc.freeze doc.destroyed = true end end
#pre_process_batch_insert(docs) ⇒ Array<Hash> (private)
Pre processes the batch insert for the provided documents.
# File 'lib/mongoid/association/embedded/batchable.rb', line 315
def pre_process_batch_insert(docs) docs.map do |doc| next unless doc append(doc) if persistable? && !_assigning? self.path = doc.atomic_path unless path if doc.valid?(:create) doc.run_before_callbacks(:save, :create) else self.inserts_valid = false end end doc.send(:as_attributes) end end
#pre_process_batch_remove(docs, method) ⇒ Array<Hash> (private)
Pre process the batch removal.
# File 'lib/mongoid/association/embedded/batchable.rb', line 342
def pre_process_batch_remove(docs, method) docs.map do |doc| self.path = doc.atomic_path unless path execute_callback :before_remove, doc unless _assigning? doc.apply_destroy_dependencies! doc.run_before_callbacks(:destroy) if method == :destroy end _target.delete_one(doc) _unscoped.delete_one(doc) unbind_one(doc) execute_callback :after_remove, doc doc.send(:as_attributes) end end
#selector ⇒ Hash (private)
Get the selector for executing atomic operations on the collection.
# File 'lib/mongoid/association/embedded/batchable.rb', line 301
def selector @selector ||= _base.atomic_selector end