class Moped::Query

The Query class encapsulates all of the logic related to building selectors for querying, updating, or removing documents in a collection.

@example

people = db[:people]
people.find.entries # => [{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}]
people.find.skip(2).first # => { id: 3 }
people.find.skip(2).update(name: "John")
people.find.skip(2).first # => { id: 3, name: "John" }

people.find(name: nil).update_all(name: "Unknown")
people.find.one # => { id: 5, name: "Unknown" }
people.find.first # => { id: 5, name: "Unknown" }
people.find.select(name: 0).first # => { id: 5 }
people.find(name: "Unknown").remove_all
people.find.count # => 1

Attributes

collection[R]

@attribute [r] collection The collection to execute the query on. @attribute [r] operation The query operation. @attribute [r] selector The query selector.

operation[R]

@attribute [r] collection The collection to execute the query on. @attribute [r] operation The query operation. @attribute [r] selector The query selector.

selector[R]

@attribute [r] collection The collection to execute the query on. @attribute [r] operation The query operation. @attribute [r] selector The query selector.

Public Class Methods

new(collection, selector) click to toggle source

Initialize the query.

@example Initialize the query.

Query.new(collection, selector)

@param [ Collection ] collection The query's collection. @param [ Hash ] selector The query's selector.

@since 1.0.0

# File lib/moped/query.rb, line 169
def initialize(collection, selector)
  @collection, @selector = collection, selector
  @operation = Protocol::Query.new(
    collection.database.name,
    collection.name,
    selector
  )
end

Public Instance Methods

batch_size(batch_size) click to toggle source

Set the query's batch size.

@example Set the batch size.

db[:people].find.batch_size(20)

@param [ Integer ] limit The number of documents per batch.

@return [ Query ] self

@since 1.0.0

# File lib/moped/query.rb, line 203
def batch_size(batch_size)
  operation.batch_size = batch_size
  self
end
count(limit = false) click to toggle source

Get the count of matching documents in the query.

@example Get the count.

db[:people].find.count

@return [ Integer ] The number of documents that match the selector.

@since 1.0.0

# File lib/moped/query.rb, line 35
def count(limit = false)
  command = { count: collection.name, query: selector }
  command.merge!(skip: operation.skip, limit: operation.limit) if limit
  result = collection.database.command(command)
  result["n"].to_i
end
cursor() click to toggle source
Alias for: each
distinct(key) click to toggle source

Get the distinct values in the collection for the provided key.

@example Get the distinct values.

db[:people].find.distinct(:name)

@param [ Symbol, String ] key The name of the field.

@return [ Array<Object ] The distinct values.

@since 1.0.0

# File lib/moped/query.rb, line 52
def distinct(key)
  result = collection.database.command(
    distinct: collection.name,
    key: key.to_s,
    query: selector
  )
  result["values"]
end
each() { |document| ... } click to toggle source

Iterate through documents matching the query's selector.

@example Iterate over the matching documents.

db[:people].find.each do |doc|
  #...
end

@return [ Enumerator ] The enumerator.

@since 1.0.0

@yieldparam [ Hash ] document each matching document

# File lib/moped/query.rb, line 73
def each
  cursor = Cursor.new(session, operation)
  enum = cursor.to_enum
  enum.each do |document|
    yield document
  end if block_given?
  enum
end
Also aliased as: cursor
explain() click to toggle source

Explain the current query.

@example Explain the query.

db[:people].find.explain

@return [ Hash ] The explain document.

@since 1.0.0

# File lib/moped/query.rb, line 91
def explain
  explanation = operation.selector.dup
  hint = explanation["$hint"]
  sort = explanation["$orderby"]
  max_scan = explanation["$maxScan"]
  explanation = {
    "$query" => selector,
    "$explain" => true,
  }
  explanation["$orderby"] = sort if sort
  explanation["$hint"] = hint if hint
  explanation["$maxScan"] = max_scan if max_scan
  Query.new(collection, explanation).limit(-(operation.limit.abs)).each { |doc| return doc }
end
first() click to toggle source

Get the first matching document.

@example Get the first matching document.

db[:people].find.first

@return [ Hash ] The first document that matches the selector.

@since 1.0.0

# File lib/moped/query.rb, line 114
def first
  reply = session.context.query(
    operation.database,
    operation.collection,
    operation.selector,
    fields: operation.fields,
    flags: operation.flags,
    skip: operation.skip,
    limit: -1
  )
  reply.documents.first
end
Also aliased as: one
hint(hint) click to toggle source

Apply an index hint to the query.

@example Apply an index hint.

db[:people].find.hint("$natural" => 1)

@param [ Hash ] hint The index hint.

@return [ Query ] self

@since 1.0.0

# File lib/moped/query.rb, line 138
def hint(hint)
  upgrade_to_advanced_selector
  operation.selector["$hint"] = hint
  self
end
limit(limit) click to toggle source

Set the query's limit.

@example Set the limit.

db[:people].find.limit(20)

@param [ Integer ] limit The number of documents to limit.

@return [ Query ] self

@since 1.0.0

# File lib/moped/query.rb, line 188
def limit(limit)
  operation.limit = limit
  self
end
max_scan(max) click to toggle source

Apply a max scan limit to the query.

@example Limit the query to only scan up to 100 documents

db[:people].find.max_scan(100)

@param [ Integer ] max The maximum number of documents to scan

@return [ Query ] self

@since 1.4.0

# File lib/moped/query.rb, line 154
def max_scan(max)
  upgrade_to_advanced_selector
  operation.selector["$maxScan"] = max
  self
end
modify(change, options = {}) click to toggle source

Execute a $findAndModify on the query.

@example Find and modify a document, returning the original.

db[:bands].find.modify({ "$inc" => { likes: 1 }})

@example Find and modify a document, returning the updated document.

db[:bands].find.modify({ "$inc" => { likes: 1 }}, new: true)

@example Find and return a document, removing it from the database.

db[:bands].find.modify({}, remove: true)

@example Find and return a document, upserting if no match found.

db[:bands].find.modify({}, upsert: true, new: true)

@param [ Hash ] change The changes to make to the document. @param [ Hash ] options The options.

@option options :new Set to true if you want to return the updated document. @option options :remove Set to true if the document should be deleted. @option options :upsert Set to true if you want to upsert

@return [ Hash ] The document.

@since 1.0.0

# File lib/moped/query.rb, line 245
def modify(change, options = {})
  command = {
    findAndModify: collection.name,
    query: selector
  }.merge(options)

  command[:sort] = operation.selector["$orderby"] if operation.selector["$orderby"]
  command[:fields] = operation.fields if operation.fields
  command[:update] = change unless options[:remove]

  result = session.with(consistency: :strong) do |sess|
    sess.command(command)["value"]
  end

  # Keeping moped compatibility with mongodb >= 2.2.0-rc0
  options[:upsert] && !result ? {} : result
end
no_timeout() click to toggle source

Disable cursor timeout

@example Disable cursor timeout.

db[:people].find.no_timeout

@return [ Query ] self

@since 1.0.0

# File lib/moped/query.rb, line 216
def no_timeout
  operation.no_timeout = true
  self
end
one() click to toggle source
Alias for: first
remove() click to toggle source

Remove a single document matching the query's selector.

@example Remove a single document.

db[:people].find(name: "John").remove

@return [ Hash, nil ] If in safe mode the last error result.

@since 1.0.0

# File lib/moped/query.rb, line 271
def remove
  session.with(consistency: :strong) do |session|
    session.context.remove(
      operation.database,
      operation.collection,
      operation.basic_selector,
      flags: [ :remove_first ]
    )
  end
end
remove_all() click to toggle source

Remove multiple documents matching the query's selector.

@example Remove all matching documents.

db[:people].find(name: "John").remove_all

@return [ Hash, nil ] If in safe mode the last error result.

@since 1.0.0

# File lib/moped/query.rb, line 290
def remove_all
  session.with(consistency: :strong) do |session|
    session.context.remove(
      operation.database,
      operation.collection,
      operation.basic_selector
    )
  end
end
select(select) click to toggle source

Set the fields to include or exclude from the query.

@example Select the fields to include or exclude.

db[:people].find.select(name: 1).one # => { name: "John" }

@param [ Hash ] select The inclusions or exclusions.

@return [ Query ] self

@since 1.0.0

# File lib/moped/query.rb, line 310
def select(select)
  operation.fields = select
  self
end
skip(skip) click to toggle source

Set the number of documents to skip.

@example Set the number to skip.

db[:people].find.skip(20)

@param [ Integer ] skip The number of documents to skip.

@return [ Query ] self

@since 1.0.0

# File lib/moped/query.rb, line 325
def skip(skip)
  operation.skip = skip
  self
end
sort(sort) click to toggle source

Set the sort order for the query.

@example Set the sort order.

db[:people].find.sort(name: 1, age: -1).one

@param [ Hash ] sort The order as key/(1/-1) pairs.

@return [ Query ] self

@since 1.0.0

# File lib/moped/query.rb, line 340
def sort(sort)
  upgrade_to_advanced_selector
  operation.selector["$orderby"] = sort
  self
end
tailable() click to toggle source

Tell the query to create a tailable cursor.

@example Tell the query the cursor is tailable.

db[:people].find.tailable

@return [ Query ] The query.

@since 1.3.0

# File lib/moped/query.rb, line 354
def tailable
  operation.flags.push(:tailable, :await_data)
  self
end
update(change, flags = nil) click to toggle source

Update a single document matching the query's selector.

@example Update the first matching document.

db[:people].find(_id: 1).update(name: "John")

@param [ Hash ] change The changes to make to the document @param [ Array ] flags An array of operation flags. Valid values are:

+:multi+ and +:upsert+

@return [ Hash, nil ] If in safe mode the last error result.

@since 1.0.0

# File lib/moped/query.rb, line 371
def update(change, flags = nil)
  session.with(consistency: :strong) do |session|
    session.context.update(
      operation.database,
      operation.collection,
      operation.selector["$query"] || operation.selector,
      change,
      flags: flags
    )
  end
end
update_all(change) click to toggle source

Update multiple documents matching the query's selector.

@example Update multiple documents.

db[:people].find(name: "John").update_all(name: "Mary")

@param [ Hash ] change The changes to make to the documents

@return [ Hash, nil ] If in safe mode the last error result.

@since 1.0.0

# File lib/moped/query.rb, line 393
def update_all(change)
  update(change, [ :multi ])
end
upsert(change) click to toggle source

Update an existing document with change, otherwise create one.

@example Upsert the changes.

db[:people].find.entries # => { name: "John" }
db[:people].find(name: "John").upsert(name: "James")
db[:people].find.entries # => { name: "James" }
db[:people].find(name: "John").upsert(name: "Mary")
db[:people].find.entries # => [{ name: "James" }, { name: "Mary" }]

@param [ Hash ] change The changes to make to the the document.

@return [ Hash, nil ] If in safe mode the last error result.

@since 1.0.0

# File lib/moped/query.rb, line 411
def upsert(change)
  update(change, [ :upsert ])
end