123456789_123456789_123456789_123456789_123456789_

Class: Mongoid::Contextual::Memory

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: lib/mongoid/contextual/memory.rb

Overview

Context object used for performing bulk query and persistence operations on documents which have been loaded into application memory. The method interface of this class is consistent with Mongoid::Contextual::Mongo.

Class Method Summary

Instance Attribute Summary

Queryable - Included

::Mongoid::Association::EagerLoadable - Included

#eager_loadable?

Indicates whether the criteria has association inclusions which should be eager loaded.

Instance Method Summary

::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

::Mongoid::Association::EagerLoadable - Included

#eager_load

Load the associations for the given documents.

#preload

Load the associations for the given documents.

Aggregable::Memory - Included

#aggregates

Get all the aggregate values for the provided field.

#avg

Get the average value of the provided field.

#max

Get the max value of the provided field.

#min

Get the min value of the provided field.

#sum

Get the sum value of the provided field.

#aggregate_by

Aggregate by the provided field and method.

Constructor Details

.new(criteria) ⇒ Memory

Create the new in memory context.

Examples:

Create the new context.

Memory.new(criteria)

Parameters:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 173

def initialize(criteria)
  @criteria, @klass = criteria, criteria.klass
  @documents = criteria.documents.select do |doc|
    @root ||= doc._root
    @collection ||= root.collection
    doc._matches?(criteria.selector)
  end
  apply_sorting
  apply_options
end

Instance Attribute Details

#documents (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#limitingInteger (rw, private)

This method is for internal use only.

Get the limiting value.

Examples:

Get the limiting value.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 566

def limiting
  defined?(@limiting) ? @limiting : nil
end

#limiting=(value) ⇒ Integer (rw, private)

This method is for internal use only.

::Set the limiting value.

Examples:

::Set the limiting value.

Parameters:

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 579

def limiting=(value)
  @limiting = value
end

#matching The in memory documents that match the selector.(The in memory documents that match the selector.) (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#path (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#path The atomic path.(The atomic path.) (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#root (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#root The root document.(The root document.) (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#selector (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#selector The root document selector.(The root document selector.) (readonly)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 25

attr_reader :documents, :path, :root, :selector

#skippingInteger (rw, private)

This method is for internal use only.

Get the skipping value.

Examples:

Get the skipping value.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 590

def skipping
  defined?(@skipping) ? @skipping : nil
end

#skipping=(value) ⇒ Integer (rw, private)

This method is for internal use only.

::Set the skipping value.

Examples:

::Set the skipping value.

Parameters:

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 603

def skipping=(value)
  @skipping = value
end

Instance Method Details

#==(other) ⇒ true | false

Check if the context is equal to the other object.

Examples:

Check equality.

context == []

Parameters:

  • other (Array)

    The other array.

Returns:

  • (true | false)

    If the objects are equal.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 35

def ==(other)
  return false unless other.respond_to?(:entries)
  entries == other.entries
end

#_session (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 682

def _session
  @criteria.send(:_session)
end

#apply_optionsMemory (private)

This method is for internal use only.

Apply criteria options.

Examples:

Apply criteria options.

context.apply_options

Returns:

  • (Memory)

    self.

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 615

def apply_options
  raise Errors::InMemoryCollationNotSupported.new if criteria.options[:collation]
  skip(criteria.options[:skip]).limit(criteria.options[:limit])
end

#apply_sorting (private)

Map the sort symbols to the correct MongoDB values.

Examples:

Apply the sorting params.

context.apply_sorting
[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 624

def apply_sorting
  if spec = criteria.options[:sort]
    in_place_sort(spec)
  end
end

#compare(a, b) ⇒ Integer (private)

This method is for internal use only.

Compare two values, handling the cases when either value is nil.

Examples:

Compare the two objects.

context.compare(a, b)

Parameters:

  • a (Object)

    The first object.

  • b (Object)

    The second object.

Returns:

  • (Integer)

    The comparison value.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 642

def compare(a, b)
  return 0 if a.nil? && b.nil?
  return 1 if a.nil?
  return -1 if b.nil?

  compare_operand(a) <=> compare_operand(b)
end

#compare_operand(value) ⇒ Integer | Object (private)

Get the operand value to be used in comparison. Adds capability to sort boolean values.

Examples:

Get the comparison operand.

compare_operand(true) #=> 1

Parameters:

  • value (Object)

    The value to be used in comparison.

Returns:

  • (Integer | Object)

    The comparison operand.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 695

def compare_operand(value)
  case value
  when TrueClass then 1
  when FalseClass then 0
  else value
  end
end

#deletenil Also known as: #delete_all

Delete all documents in the database that match the selector.

Examples:

Delete all the documents.

context.delete

Returns:

  • (nil)

    Nil.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 46

def delete
  deleted = count
  removed = map do |doc|
    prepare_remove(doc)
    doc.send(:as_attributes)
  end
  unless removed.empty?
    collection.find(selector).update_one(
      positionally(selector, "$pullAll" => { path => removed }),
      session: _session
    )
  end
  deleted
end

#delete_all

Alias for #delete.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 60

alias :delete_all :delete

#destroynil Also known as: #destroy_all

Destroy all documents in the database that match the selector.

Examples:

Destroy all the documents.

context.destroy

Returns:

  • (nil)

    Nil.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 68

def destroy
  deleted = count
  each do |doc|
    documents.delete_one(doc)
    doc.destroy
  end
  deleted
end

#destroy_all

Alias for #destroy.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 76

alias :destroy_all :destroy

#distinct(field) ⇒ Array<Object>

Get the distinct values in the db for the provided field.

Examples:

Get the distinct values.

context.distinct(:name)

Parameters:

Returns:

  • (Array<Object>)

    The distinct values for the field.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 86

def distinct(field)
  pluck(field).uniq
end

#documents_for_iterationArray<Document> (private)

This method is for internal use only.

Get the documents the context should iterate. This follows 3 rules:

Examples:

Get the documents for iteration.

context.documents_for_iteration

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 530

def documents_for_iteration
  docs = documents[skipping || 0, limiting || documents.length] || []
  if eager_loadable?
    eager_load(docs)
  end
  docs
end

#eachEnumerator

Iterate over the context. If provided a block, yield to a ::Mongoid document for each, otherwise return an enum.

Examples:

Iterate over the context.

context.each do |doc|
  puts doc.name
end

Returns:

  • (Enumerator)

    The enumerator.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 99

def each
  if block_given?
    documents_for_iteration.each do |doc|
      yield(doc)
    end
    self
  else
    to_enum
  end
end

#exists?(id_or_conditions = :none) ⇒ true | false

Do any documents exist for the context.

Examples:

Do any documents exist for the context.

context.exists?

Do any documents exist for given _id.

context.exists?(BSON::ObjectId(...))

Do any documents exist for given conditions.

context.exists?(name: "...")

Parameters:

  • id_or_conditions (Hash | Object | false) (defaults to: :none)

    an _id to search for, a hash of conditions, nil or false.

Returns:

  • (true | false)

    If the count is more than zero. Always false if passed nil or false.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 126

def exists?(id_or_conditions = :none)
  case id_or_conditions
  when :none then any?
  when nil, false then false
  when Hash then Memory.new(criteria.where(id_or_conditions)).exists?
  else Memory.new(criteria.where(_id: id_or_conditions)).exists?
  end
end

#fifthDocument

Get the fifth document in the database for the criteria’s selector.

Examples:

Get the fifth document.

context.fifth

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 454

def fifth
  eager_load([documents.fifth]).first
end

#fifth!Document

Get the fifth document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the fifth document.

context.fifth!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 468

def fifth!
  fifth || raise_document_not_found_error
end

#find_first(limit = nil)

Alias for #first.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 151

alias :find_first :first

#first(limit = nil) ⇒ Document Also known as: #one, #find_first

Get the first document in the database for the criteria’s selector.

Examples:

Get the first document.

context.first

Parameters:

  • limit (Integer) (defaults to: nil)

    The number of documents to return.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 143

def first(limit = nil)
  if limit
    eager_load(documents.first(limit))
  else
    eager_load([documents.first]).first
  end
end

#first!Document

Get the first document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the first document.

context.first!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 163

def first!
  first || raise_document_not_found_error
end

#fourthDocument

Get the fourth document in the database for the criteria’s selector.

Examples:

Get the fourth document.

context.fourth

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 430

def fourth
  eager_load([documents.fourth]).first
end

#fourth!Document

Get the fourth document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the fourth document.

context.fourth!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 444

def fourth!
  fourth || raise_document_not_found_error
end

#in_place_sort(values) (private)

Sort the documents in place.

Examples:

Sort the documents.

context.in_place_sort(name: 1)

Parameters:

  • values (Hash)

    The field/direction sorting pairs.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 656

def in_place_sort(values)
  documents.sort! do |a, b|
    values.map do |field, direction|
      direction * compare(a[field], b[field])
    end.detect { |value| !value.zero? } || 0
  end
end

#inc(incs) ⇒ Enumerator

Increment a value on all documents.

Examples:

Perform the increment.

context.inc(likes: 10)

Parameters:

  • incs (Hash)

    The operations.

Returns:

  • (Enumerator)

    The enumerator.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 192

def inc(incs)
  each do |document|
    document.inc(incs)
  end
end

#last(limit = nil) ⇒ Document

Get the last document in the database for the criteria’s selector.

Examples:

Get the last document.

context.last

Parameters:

  • limit (Integer) (defaults to: nil)

    The number of documents to return.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 206

def last(limit = nil)
  if limit
    eager_load(documents.last(limit))
  else
    eager_load([documents.last]).first
  end
end

#last!Document

Get the last document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the last document.

context.last!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 224

def last!
  last || raise_document_not_found_error
end

#lengthInteger Also known as: #size

Get the length of matching documents in the context.

Examples:

Get the length of matching documents.

context.length

Returns:

  • (Integer)

    The matching length.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 234

def length
  documents.length
end

#limit(value) ⇒ Memory

Limits the number of documents that are returned.

Examples:

Limit the documents.

context.limit(20)

Parameters:

  • value (Integer)

    The number of documents to return.

Returns:

  • (Memory)

    The context.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 247

def limit(value)
  self.limiting = value
  self
end

#one(limit = nil)

Alias for #first.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 150

alias :one :first

#pick(*fields) ⇒ Object | Array<Object>

Pick the field values in memory.

Examples:

Get the values in memory.

context.pick(:name)

Parameters:

Returns:

  • (Object | Array<Object>)

    The picked values.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 274

def pick(*fields)
  if doc = documents.first
    pluck_from_doc(doc, *fields)
  end
end

#pluck(*fields) ⇒ Array<Object> | Array<Array<Object>>

Pluck the field values in memory.

Examples:

Get the values in memory.

context.pluck(:name)

Parameters:

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 260

def pluck(*fields)
  documents.map do |doc|
    pluck_from_doc(doc, *fields)
  end
end

#pluck_from_doc(doc, *fields) ⇒ Object | Array<Object> (private)

Pluck the field values from the given document.

Parameters:

  • doc (Document)

    The document to pluck from.

  • *fields ([ String | Symbol ]...)

    Field(s) to pluck.

Returns:

  • (Object | Array<Object>)

    The plucked values.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 766

def pluck_from_doc(doc, *fields)
  if fields.length == 1
    retrieve_value_at_path(doc, fields.first)
  else
    fields.map do |field|
      retrieve_value_at_path(doc, field)
    end
  end
end

#prepare_remove(doc) (private)

This method is for internal use only.

Prepare the document for batch removal.

Examples:

Prepare for removal.

context.prepare_remove(doc)

Parameters:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 672

def prepare_remove(doc)
  @selector ||= root.atomic_selector
  @path ||= doc.atomic_path
  documents.delete_one(doc)
  doc._parent.remove_child(doc)
  doc.destroyed = true
end

#raise_document_not_found_error (private)

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 776

def raise_document_not_found_error
  raise Errors::DocumentNotFound.new(klass, nil, nil)
end

#retrieve_value_at_path(document, field_path) ⇒ Object | nil (private)

Retrieve the value for the current document at the given field path.

For example, if I have the following models:

User has_many Accounts
address is a hash on Account

u = User.new(accounts: [ Account.new(address: { street: "W 50th" }) ])
retrieve_value_at_path(u, "user.accounts.address.street")
# => [ "W 50th" ]

Note that the result is in an array since accounts is an array. If it was nested in two arrays the result would be in a 2D array.

Parameters:

  • document (Object)

    The object to traverse the field path.

  • field_path (String)

    The dotted string that represents the path to the value.

Returns:

  • (Object | nil)

    The value at the given field path or nil if it doesn’t exist.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 723

def retrieve_value_at_path(document, field_path)
  return if field_path.blank? || !document
  segment, remaining = field_path.to_s.split('.', 2)

  curr = if document.is_a?(Document)
    # Retrieves field for segment to check localization. Only does one
    # iteration since there's no dots
    res = if remaining
      field = document.class.traverse_association_tree(segment)
      # If this is a localized field, and there are remaining, get the
      # _translations hash so that we can get the specified translation in
      # the remaining
      if field&.localized?
        document.send("#{segment}_translations")
      end
    end
    meth = klass.aliased_associations[segment] || segment
    res.nil? ? document.try(meth) : res
  elsif document.is_a?(Hash)
    # TODO: Remove the indifferent access when implementing MONGOID-5410.
    document.key?(segment.to_s) ?
      document[segment.to_s] :
      document[segment.to_sym]
  else
    nil
  end

  return curr unless remaining

  if curr.is_a?(Array)
    # compact is used for consistency with server behavior.
    curr.map { |d| retrieve_value_at_path(d, remaining) }.compact
  else
    retrieve_value_at_path(curr, remaining)
  end
end

#secondDocument

Get the second document in the database for the criteria’s selector.

Examples:

Get the second document.

context.second

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 382

def second
  eager_load([documents.second]).first
end

#second!Document

Get the second document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the second document.

context.second!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 396

def second!
  second || raise_document_not_found_error
end

#second_to_lastDocument

Get the second to last document in the database for the criteria’s selector.

Examples:

Get the second to last document.

context.second_to_last

Returns:

  • (Document)

    The second to last document.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 478

def second_to_last
  eager_load([documents.second_to_last]).first
end

#second_to_last!Document

Get the second to last document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the second to last document.

context.second_to_last!

Returns:

  • (Document)

    The second to last document.

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 492

def second_to_last!
  second_to_last || raise_document_not_found_error
end

#size

Alias for #length.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 237

alias :size :length

#skip(value) ⇒ Memory

Skips the provided number of documents.

Examples:

Skip the documents.

context.skip(20)

Parameters:

  • value (Integer)

    The number of documents to skip.

Returns:

  • (Memory)

    The context.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 334

def skip(value)
  self.skipping = value
  self
end

#sort(values) ⇒ Memory

Sorts the documents by the provided spec.

Examples:

Sort the documents.

context.sort(name: -1, title: 1)

Parameters:

  • values (Hash)

    The sorting values as field/direction(1/-1) pairs.

Returns:

  • (Memory)

    The context.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 348

def sort(values)
  in_place_sort(values) and self
end

#take(limit = nil) ⇒ Document

Take the given number of documents from the database.

Examples:

Take a document.

context.take

Parameters:

  • limit (Integer | nil) (defaults to: nil)

    The number of documents to take or nil.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 304

def take(limit = nil)
  if limit
    eager_load(documents.take(limit))
  else
    eager_load([documents.first]).first
  end
end

#take!Document

Take the given number of documents from the database or raise an error if none are found.

Examples:

Take a document.

context.take

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 322

def take!
  take || raise_document_not_found_error
end

#tally(field) ⇒ Hash

Tally the field values in memory.

Examples:

Get the counts of values in memory.

context.tally(:name)

Parameters:

Returns:

  • (Hash)

    The hash of counts.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 288

def tally(field)
  return documents.each_with_object({}) do |d, acc|
    v = retrieve_value_at_path(d, field)
    acc[v] ||= 0
    acc[v] += 1
  end
end

#thirdDocument

Get the third document in the database for the criteria’s selector.

Examples:

Get the third document.

context.third

Returns:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 406

def third
  eager_load([documents.third]).first
end

#third!Document

Get the third document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the third document.

context.third!

Returns:

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 420

def third!
  third || raise_document_not_found_error
end

#third_to_lastDocument

Get the third to last document in the database for the criteria’s selector.

Examples:

Get the third to last document.

context.third_to_last

Returns:

  • (Document)

    The third to last document.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 502

def third_to_last
  eager_load([documents.third_to_last]).first
end

#third_to_last!Document

Get the third to last document in the database for the criteria’s selector or raise an error if none is found.

Examples:

Get the third to last document.

context.third_to_last!

Returns:

  • (Document)

    The third to last document.

Raises:

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 516

def third_to_last!
  third_to_last || raise_document_not_found_error
end

#update(attributes = nil) ⇒ nil | false

Update the first matching document atomically.

Examples:

Update the matching document.

context.update(name: "Smiths")

Parameters:

  • attributes (Hash) (defaults to: nil)

    The new attributes for the document.

Returns:

  • (nil | false)

    False if no attributes were provided.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 360

def update(attributes = nil)
  update_documents(attributes, [ first ])
end

#update_all(attributes = nil) ⇒ nil | false

Update all the matching documents atomically.

Examples:

Update all the matching documents.

context.update_all(name: "Smiths")

Parameters:

  • attributes (Hash) (defaults to: nil)

    The new attributes for each document.

Returns:

  • (nil | false)

    False if no attributes were provided.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 372

def update_all(attributes = nil)
  update_documents(attributes, entries)
end

#update_documents(attributes, docs) (private)

This method is for internal use only.

Update the provided documents with the attributes.

Examples:

Update the documents.

context.update_documents({}, doc)

Parameters:

  • attributes (Hash)

    The attributes.

  • docs (Array<Document>)

    The docs to update.

[ GitHub ]

  
# File 'lib/mongoid/contextual/memory.rb', line 547

def update_documents(attributes, docs)
  return false if !attributes || docs.empty?
  updates = { "$set" => {}}
  docs.each do |doc|
    @selector ||= root.atomic_selector
    doc.write_attributes(attributes)
    updates["$set"].merge!(doc.atomic_updates["$set"] || {})
    doc.move_changes
  end
  collection.find(selector).update_one(updates, session: _session) unless updates["$set"].empty?
end