Class: Mongoid::Contextual::Mongo

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable, Association::EagerLoadable, Atomic, Aggregable::Mongo, Queryable
Defined in:
lib/mongoid/contextual/mongo.rb

Constant Summary collapse

OPTIONS =

Options constant.

[ :hint,
  :limit,
  :skip,
  :sort,
  :batch_size,
  :max_scan,
  :max_time_ms,
  :snapshot,
  :comment,
  :read,
  :cursor_type,
  :collation
].freeze

Constants included from Atomic

Atomic::UPDATES

Instance Attribute Summary collapse

Attributes included from Queryable

#collection, #collection The collection to query against., #criteria, #criteria The criteria for the context., #klass, #klass The klass for the criteria.

Instance Method Summary collapse

Methods included from Queryable

#blank?

Methods included from Association::EagerLoadable

#eager_load, #eager_loadable?, #preload

Methods included from Atomic

#add_atomic_pull, #add_atomic_unset, #atomic_array_add_to_sets, #atomic_array_pulls, #atomic_array_pushes, #atomic_attribute_name, #atomic_delete_modifier, #atomic_insert_modifier, #atomic_path, #atomic_paths, #atomic_position, #atomic_pulls, #atomic_pushes, #atomic_sets, #atomic_unsets, #atomic_updates, #delayed_atomic_pulls, #delayed_atomic_sets, #delayed_atomic_unsets, #flag_as_destroyed, #flagged_destroys, #process_flagged_destroys

Methods included from Aggregable::Mongo

#aggregates, #avg, #max, #min, #sum

Constructor Details

#initialize(criteria) ⇒ Mongo

Create the new Mongo context. This delegates operations to the underlying driver.

Examples:

Create the new context.

Mongo.new(criteria)

Parameters:



342
343
344
345
346
347
348
# File 'lib/mongoid/contextual/mongo.rb', line 342

def initialize(criteria)
  @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
  @collection = @klass.collection
  criteria.send(:merge_type_selection)
  @view = collection.find(criteria.selector, session: _session)
  apply_options
end

Instance Attribute Details

#viewObject (readonly)

Returns the value of attribute view.



36
37
38
# File 'lib/mongoid/contextual/mongo.rb', line 36

def view
  @view
end

#view The Mongo collection view.(TheMongocollectionview.) ⇒ Object (readonly)



36
# File 'lib/mongoid/contextual/mongo.rb', line 36

attr_reader :view

Instance Method Details

#cached?true, false

Is the context cached?

Examples:

Is the context cached?

context.cached?

Returns:

  • (true, false)

    If the context is cached.



44
45
46
# File 'lib/mongoid/contextual/mongo.rb', line 44

def cached?
  !!@cache
end

#count(options = {}, &block) ⇒ Integer

Get the number of documents matching the query.

Examples:

Get the number of matching documents.

context.count

Get the count of documents with the provided options.

context.count(limit: 1)

Get the count for where the provided block is true.

context.count do |doc|
  doc.likes > 1
end

Parameters:

  • options (Hash) (defaults to: {})

    The options, such as skip and limit to be factored into the count.

Returns:

  • (Integer)

    The number of matches.



65
66
67
68
# File 'lib/mongoid/contextual/mongo.rb', line 65

def count(options = {}, &block)
  return super(&block) if block_given?
  try_cache(:count) { view.count_documents(options) }
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.



95
96
97
# File 'lib/mongoid/contextual/mongo.rb', line 95

def delete
  view.delete_many.deleted_count
end

#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.



106
107
108
109
110
111
112
# File 'lib/mongoid/contextual/mongo.rb', line 106

def destroy
  each.inject(0) do |count, doc|
    doc.destroy
    count += 1 if acknowledged_write?
    count
  end
end

#distinct(field) ⇒ Array<Object>

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

Examples:

Get the distinct values.

context.distinct(:name)

Parameters:

  • field (String, Symbol)

    The name of the field.

Returns:

  • (Array<Object>)

    The distinct values for the field.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/mongoid/contextual/mongo.rb', line 123

def distinct(field)
  name = if Mongoid.legacy_pluck_distinct
    klass.database_field_name(field)
  else
    klass.cleanse_localized_field_names(field)
  end

  view.distinct(name).map do |value|
    if Mongoid.legacy_pluck_distinct
      value.class.demongoize(value)
    else
      is_translation = "#{name}_translations" == field.to_s
      recursive_demongoize(name, value, is_translation)
    end
  end
end

#each(&block) ⇒ Enumerator

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.



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/mongoid/contextual/mongo.rb', line 149

def each(&block)
  if block_given?
    documents_for_iteration.each do |doc|
      yield_document(doc, &block)
    end
    @cache_loaded = true
    self
  else
    to_enum
  end
end

#estimated_count(options = {}) ⇒ Integer

Get the estimated number of documents matching the query.

Unlike count, estimated_count does not take a block because it is not traditionally defined (with a block) on Enumarable like count is.

Examples:

Get the estimated number of matching documents.

context.estimated_count

Parameters:

  • options (Hash) (defaults to: {})

    The options, such as maxTimeMS to be factored into the count.

Returns:

  • (Integer)

    The number of matches.



82
83
84
85
86
87
# File 'lib/mongoid/contextual/mongo.rb', line 82

def estimated_count(options = {})
  unless self.criteria.selector.empty?
    raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
  end
  try_cache(:estimated_count) { view.estimated_document_count(options) }
end

#exists?true, false

Note:

We don’t use count here since Mongo does not use counted b-tree indexes, unless a count is already cached then that is used to determine the value.

Do any documents exist for the context.

Examples:

Do any documents exist for the context.

context.exists?

Returns:

  • (true, false)

    If the count is more than zero.



171
172
173
174
175
176
177
178
# File 'lib/mongoid/contextual/mongo.rb', line 171

def exists?
  return !documents.empty? if cached? && cache_loaded?
  return @count > 0 if instance_variable_defined?(:@count)

  try_cache(:exists) do
    !!(view.projection(_id: 1).limit(1).first)
  end
end

#explainHash

Run an explain on the criteria.

Examples:

Explain the criteria.

Band.where(name: "Depeche Mode").explain

Returns:

  • (Hash)

    The explain result.



186
187
188
# File 'lib/mongoid/contextual/mongo.rb', line 186

def explain
  view.explain
end

#fetch_and_demongoize(d, meth, klass) ⇒ Object



704
705
706
707
708
709
710
711
# File 'lib/mongoid/contextual/mongo.rb', line 704

def fetch_and_demongoize(d, meth, klass)
  res = d.try(:fetch, meth, nil)
  if field = klass.fields[meth]
    field.demongoize(res)
  else
    res.class.demongoize(res)
  end
end

#find_firstObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return the first result without applying sort



281
282
283
284
285
286
287
# File 'lib/mongoid/contextual/mongo.rb', line 281

def find_first
  return documents.first if cached? && cache_loaded?
  if raw_doc = view.first
    doc = Factory.from_db(klass, raw_doc, criteria)
    eager_load([doc]).first
  end
end

#find_one_and_deleteDocument

Execute the find and modify command, used for MongoDB’s $findAndModify. This deletes the found document.

Examples:

Execute the command.

context.find_one_and_delete

Returns:

  • (Document)

    The result of the command.



237
238
239
240
241
# File 'lib/mongoid/contextual/mongo.rb', line 237

def find_one_and_delete
  if doc = view.find_one_and_delete
    Factory.from_db(klass, doc)
  end
end

#find_one_and_replace(replacement, options = {}) ⇒ Document

Execute the find and modify command, used for MongoDB’s $findAndModify.

Examples:

Execute the command.

context.find_one_and_update({ likes: 1 })

Parameters:

  • replacement (Hash)

    The replacement.

  • options (Hash) (defaults to: {})

    The command options.

Options Hash (options):

  • :return_document (:before, :after)

    Return the updated document from before or after update.

  • :upsert (true, false)

    Create the document if it doesn’t exist.

Returns:

  • (Document)

    The result of the command.



224
225
226
227
228
# File 'lib/mongoid/contextual/mongo.rb', line 224

def find_one_and_replace(replacement, options = {})
  if doc = view.find_one_and_replace(replacement, options)
    Factory.from_db(klass, doc)
  end
end

#find_one_and_update(update, options = {}) ⇒ Document

Execute the find and modify command, used for MongoDB’s $findAndModify.

Examples:

Execute the command.

context.find_one_and_update({ "$inc" => { likes: 1 }})

Parameters:

  • update (Hash)

    The updates.

  • options (Hash) (defaults to: {})

    The command options.

Options Hash (options):

  • :return_document (:before, :after)

    Return the updated document from before or after update.

  • :upsert (true, false)

    Create the document if it doesn’t exist.

Returns:

  • (Document)

    The result of the command.



204
205
206
207
208
# File 'lib/mongoid/contextual/mongo.rb', line 204

def find_one_and_update(update, options = {})
  if doc = view.find_one_and_update(update, options)
    Factory.from_db(klass, doc)
  end
end

#first(opts = {}) ⇒ Document Also known as: one

Note:

Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first or #last and have no sort defined on the criteria, use the option { id_sort: :none }. Be aware that #first/#last won’t guarantee order in this case.

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

Examples:

Get the first document.

context.first

Parameters:

  • opts (Hash) (defaults to: {})

    The options for the query returning the first document.

Options Hash (opts):

  • :id_sort (:none)

    Don’t apply a sort on _id if no other sort is defined on the criteria.

Returns:



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/mongoid/contextual/mongo.rb', line 260

def first(opts = {})
  return documents.first if cached? && cache_loaded?
  try_cache(:first) do
    if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
      if raw_doc = view.sort(sort).limit(1).first
        doc = Factory.from_db(klass, raw_doc, criteria)
        eager_load([doc]).first
      end
    else
      if raw_doc = view.limit(1).first
        doc = Factory.from_db(klass, raw_doc, criteria)
        eager_load([doc]).first
      end
    end
  end
end

#geo_near(coordinates) ⇒ GeoNear

Deprecated.

Execute a $geoNear command against the database.

Examples:

Find documents close to 10, 10.

context.geo_near([ 10, 10 ])

Find with spherical distance.

context.geo_near([ 10, 10 ]).spherical

Find with a max distance.

context.geo_near([ 10, 10 ]).max_distance(0.5)

Provide a distance multiplier.

context.geo_near([ 10, 10 ]).distance_multiplier(1133)

Parameters:

  • coordinates (Array<Float>)

    The coordinates.

Returns:

  • (GeoNear)

    The GeoNear command.



308
309
310
# File 'lib/mongoid/contextual/mongo.rb', line 308

def geo_near(coordinates)
  GeoNear.new(collection, criteria, coordinates)
end

#last(opts = {}) ⇒ Object

Note:

Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first or #last and have no sort defined on the criteria, use the option { id_sort: :none }. Be aware that #first/#last won’t guarantee order in this case.

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

Examples:

Get the last document.

context.last

Parameters:

  • opts (Hash) (defaults to: {})

    The options for the query returning the first document.

Options Hash (opts):

  • :id_sort (:none)

    Don’t apply a sort on _id if no other sort is defined on the criteria.



367
368
369
370
371
372
373
374
375
376
# File 'lib/mongoid/contextual/mongo.rb', line 367

def last(opts = {})
  try_cache(:last) do
    with_inverse_sorting(opts) do
      if raw_doc = view.limit(1).first
        doc = Factory.from_db(klass, raw_doc, criteria)
        eager_load([doc]).first
      end
    end
  end
end

#lengthInteger Also known as: size

Get’s the number of documents matching the query selector.

Examples:

Get the length.

context.length

Returns:

  • (Integer)

    The number of documents.



384
385
386
# File 'lib/mongoid/contextual/mongo.rb', line 384

def length
  @length ||= self.count
end

#limit(value) ⇒ Mongo

Limits the number of documents that are returned from the database.

Examples:

Limit the documents.

context.limit(20)

Parameters:

  • value (Integer)

    The number of documents to return.

Returns:

  • (Mongo)

    The context.



397
398
399
# File 'lib/mongoid/contextual/mongo.rb', line 397

def limit(value)
  @view = view.limit(value) and self
end

#map(field = nil, &block) ⇒ Array

Invoke the block for each element of Contextual. Create a new array containing the values returned by the block.

If the symbol field name is passed instead of the block, additional optimizations would be used.

Examples:

Map by some field.

context.map(:field1)

Map with block.

context.map(&:field1)

Parameters:

  • field (Symbol) (defaults to: nil)

    The field name.

Returns:

  • (Array)

    The result of mapping.



327
328
329
330
331
332
333
# File 'lib/mongoid/contextual/mongo.rb', line 327

def map(field = nil, &block)
  if block_given?
    super(&block)
  else
    criteria.pluck(field)
  end
end

#map_reduce(map, reduce) ⇒ MapReduce

Initiate a map/reduce operation from the context.

Examples:

Initiate a map/reduce.

context.map_reduce(map, reduce)

Parameters:

  • map (String)

    The map js function.

  • reduce (String)

    The reduce js function.

Returns:

  • (MapReduce)

    The map/reduce lazy wrapper.



410
411
412
# File 'lib/mongoid/contextual/mongo.rb', line 410

def map_reduce(map, reduce)
  MapReduce.new(collection, criteria, map, reduce)
end

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

Note:

This method will return the raw db values - it performs no custom serialization.

Pluck the single field values from the database. Will return duplicates if they exist and only works for top level fields.

Examples:

Pluck a field.

context.pluck(:_id)

Parameters:

  • fields (String, Symbol, Array)

    Fields to pluck.

Returns:

  • (Array<Object, Array>)

    The plucked values.



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
# File 'lib/mongoid/contextual/mongo.rb', line 426

def pluck(*fields)
  # Multiple fields can map to the same field name. For example, plucking
  # a field and its _translations field map to the same field in the database.
  # because of this, we need to keep track of the fields requested.
  normalized_field_names = []
  normalized_select = fields.inject({}) do |hash, f|
    db_fn = klass.database_field_name(f)
    normalized_field_names.push(db_fn)

    if Mongoid.legacy_pluck_distinct
      hash[db_fn] = true
    else
      hash[klass.cleanse_localized_field_names(f)] = true
    end
    hash
  end

  view.projection(normalized_select).reduce([]) do |plucked, doc|
    values = normalized_field_names.map do |n|
      if Mongoid.legacy_pluck_distinct
        n.include?('.') ? doc[n.partition('.')[0]] : doc[n]
      else
        extract_value(doc, n)
      end
    end
    plucked << (values.size == 1 ? values.first : values)
  end
end

#skip(value) ⇒ Mongo

Skips the provided number of documents.

Examples:

Skip the documents.

context.skip(20)

Parameters:

  • value (Integer)

    The number of documents to skip.

Returns:

  • (Mongo)

    The context.



463
464
465
# File 'lib/mongoid/contextual/mongo.rb', line 463

def skip(value)
  @view = view.skip(value) and self
end

#sort(values = nil, &block) ⇒ Mongo

Sorts the documents by the provided spec.

Examples:

Sort the documents.

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

Parameters:

  • values (Hash) (defaults to: nil)

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

Returns:

  • (Mongo)

    The context.



476
477
478
479
480
481
482
483
484
485
# File 'lib/mongoid/contextual/mongo.rb', line 476

def sort(values = nil, &block)
  if block_given?
    super(&block)
  else
    # update the criteria
    @criteria = criteria.order_by(values)
    apply_option(:sort)
    self
  end
end

#update(attributes = nil, opts = {}) ⇒ nil, false

Update the first matching document atomically.

Examples:

Update the first matching document.

context.update({ "$set" => { name: "Smiths" }})

Parameters:

  • attributes (Hash) (defaults to: nil)

    The new attributes for the document.

  • opts (Hash) (defaults to: {})

    The update operation options.

Options Hash (opts):

  • :array_filters (Array)

    A set of filters specifying to which array elements an update should apply.

Returns:

  • (nil, false)

    False if no attributes were provided.



499
500
501
# File 'lib/mongoid/contextual/mongo.rb', line 499

def update(attributes = nil, opts = {})
  update_documents(attributes, :update_one, opts)
end

#update_all(attributes = nil, opts = {}) ⇒ nil, false

Update all the matching documents atomically.

Examples:

Update all the matching documents.

context.update_all({ "$set" => { name: "Smiths" }})

Parameters:

  • attributes (Hash) (defaults to: nil)

    The new attributes for each document.

  • opts (Hash) (defaults to: {})

    The update operation options.

Options Hash (opts):

  • :array_filters (Array)

    A set of filters specifying to which array elements an update should apply.

Returns:

  • (nil, false)

    False if no attributes were provided.



515
516
517
# File 'lib/mongoid/contextual/mongo.rb', line 515

def update_all(attributes = nil, opts = {})
  update_documents(attributes, :update_many, opts)
end