Class: Moped::Query

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/moped/query.rb

Overview

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

Examples:

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("$set" => { 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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(collection, selector) ⇒ Query

Initialize the query.

Examples:

Initialize the query.

Query.new(collection, selector)

Parameters:

  • collection (Collection)

    The query’s collection.

  • selector (Hash)

    The query’s selector.

Since:

  • 1.0.0



221
222
223
224
225
226
227
228
# File 'lib/moped/query.rb', line 221

def initialize(collection, selector)
  @collection, @selector = collection, selector
  @operation = Protocol::Query.new(
    collection.database.name,
    collection.name,
    selector
  )
end

Instance Attribute Details

#collectionObject (readonly)

Returns the value of attribute collection.



28
29
30
# File 'lib/moped/query.rb', line 28

def collection
  @collection
end

#collection The collection to execute the query on.(Thecollectiontoexecutethequeryon.) ⇒ Object (readonly)



28
# File 'lib/moped/query.rb', line 28

attr_reader :collection, :operation, :selector

#operationObject (readonly)

Returns the value of attribute operation.



28
29
30
# File 'lib/moped/query.rb', line 28

def operation
  @operation
end

#operation The query operation.(Thequeryoperation.) ⇒ Object (readonly)



28
# File 'lib/moped/query.rb', line 28

attr_reader :collection, :operation, :selector

#selectorObject (readonly)

Returns the value of attribute selector.



28
29
30
# File 'lib/moped/query.rb', line 28

def selector
  @selector
end

#selector The query selector.(Thequeryselector.) ⇒ Object (readonly)



28
# File 'lib/moped/query.rb', line 28

attr_reader :collection, :operation, :selector

Instance Method Details

#batch_size(batch_size) ⇒ Query

Set the query’s batch size.

Examples:

Set the batch size.

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

Parameters:

  • limit (Integer)

    The number of documents per batch.

Returns:

Since:

  • 1.0.0



255
256
257
258
# File 'lib/moped/query.rb', line 255

def batch_size(batch_size)
  operation.batch_size = batch_size
  self
end

#clusterObject



478
479
480
# File 'lib/moped/query.rb', line 478

def cluster
  session.cluster
end

#count(limit = false) ⇒ Integer

Get the count of matching documents in the query.

Examples:

Get the count.

db[:people].find.count

Returns:

  • (Integer)

    The number of documents that match the selector.

Since:

  • 1.0.0



38
39
40
41
42
43
# File 'lib/moped/query.rb', line 38

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

#cursorMoped::Cursor

Get the Moped cursor to iterate over documents on the db.

Examples:

Iterate over the matching documents.

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

Returns:

Since:

  • 2.0.0



91
92
93
# File 'lib/moped/query.rb', line 91

def cursor
  Cursor.new(session, operation)
end

#distinct(key) ⇒ Array<Object ] The distinct values.

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

Examples:

Get the distinct values.

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

Parameters:

  • key (Symbol, String)

    The name of the field.

Returns:

  • (Array<Object ] The distinct values.)

    Array<Object ] The distinct values.

Since:

  • 1.0.0



55
56
57
58
59
60
61
62
# File 'lib/moped/query.rb', line 55

def distinct(key)
  result = collection.database.command(
    distinct: collection.name,
    key: key.to_s,
    query: selector
  )
  result["values"]
end

#each(*args) {|document| ... } ⇒ Enumerable

Iterate through documents matching the query’s selector.

Examples:

Iterate over the matching documents.

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

Yield Parameters:

  • document (Hash)

    each matching document

Returns:

  • (Enumerable)

Since:

  • 1.0.0



76
77
78
# File 'lib/moped/query.rb', line 76

def each(*args, &blk)
  cursor.each(*args, &blk)
end

#explainHash

Explain the current query.

Examples:

Explain the query.

db[:people].find.explain

Returns:

  • (Hash)

    The explain document.

Since:

  • 1.0.0



103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/moped/query.rb', line 103

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

#firstHash Also known as: one

Get the first matching document.

Examples:

Get the first matching document.

db[:people].find.first

Returns:

  • (Hash)

    The first document that matches the selector.

Since:

  • 1.0.0



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/moped/query.rb', line 126

def first
  reply = read_preference.with_node(cluster) do |node|
    node.query(
      operation.database,
      operation.collection,
      operation.selector,
      query_options(
        fields: operation.fields,
        flags: operation.flags,
        skip: operation.skip,
        limit: -1
      )
    )
  end
  reply.documents.first
end

#hint(hint) ⇒ Query

Apply an index hint to the query.

Examples:

Apply an index hint.

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

Parameters:

  • hint (Hash)

    The index hint.

Returns:

Since:

  • 1.0.0



154
155
156
157
158
# File 'lib/moped/query.rb', line 154

def hint(hint)
  upgrade_to_advanced_selector
  operation.selector["$hint"] = hint
  self
end

#limit(limit) ⇒ Query

Set the query’s limit.

Examples:

Set the limit.

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

Parameters:

  • limit (Integer)

    The number of documents to limit.

Returns:

Since:

  • 1.0.0



240
241
242
243
# File 'lib/moped/query.rb', line 240

def limit(limit)
  operation.limit = limit
  self
end

#max(index_bounds) ⇒ Query

Specifies the exclusive upper bound for a specific index in order to constrain the results of find(). max() provides a way to specify an upper bound on compound key indexes.

(provided the collection has a => -11 index)

db[:people].find.min("age" => 21)

Examples:

Set the upper bond on the age index to 21 years

Parameters:

  • indexBounds (Hash)

    The exclusive upper bound for the index keys.

Returns:



206
207
208
209
210
# File 'lib/moped/query.rb', line 206

def max(index_bounds)
  upgrade_to_advanced_selector
  operation.selector["$max"] = index_bounds
  self
end

#max_scan(max) ⇒ Query

Apply a max scan limit to the query.

Examples:

Limit the query to only scan up to 100 documents

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

Parameters:

  • max (Integer)

    The maximum number of documents to scan

Returns:

Since:

  • 1.4.0



170
171
172
173
174
# File 'lib/moped/query.rb', line 170

def max_scan(max)
  upgrade_to_advanced_selector
  operation.selector["$maxScan"] = max
  self
end

#min(index_bounds) ⇒ Query

Specify the inclusive lower bound for a specific index in order to constrain the results of find(). min() provides a way to specify lower bounds on compound key indexes.

(provided the collection has a => 1 index)

db[:people].find.min("age" => 21)

Examples:

Set the lower bond on the age index to 21 years

Parameters:

  • indexBounds (Hash)

    The inclusive lower bound for the index keys.

Returns:



188
189
190
191
192
# File 'lib/moped/query.rb', line 188

def min(index_bounds)
  upgrade_to_advanced_selector
  operation.selector["$min"] = index_bounds
  self
end

#modify(change, options = {}) ⇒ Hash

Execute a $findAndModify on the query.

Examples:

Find and modify a document, returning the original.

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

Find and modify a document, returning the updated document.

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

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

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

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

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

Parameters:

  • change (Hash)

    The changes to make to the document.

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

    The options.

Options Hash (options):

  • :new (Object)

    Set to true if you want to return the updated document.

  • :remove (Object)

    Set to true if the document should be deleted.

  • :upsert (Object)

    Set to true if you want to upsert

Returns:

  • (Hash)

    The document.

Since:

  • 1.0.0



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/moped/query.rb', line 297

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(read: :primary) do |sess|
    sess.command(command)["value"]
  end

  # Keeping moped compatibility with mongodb >= 2.2.0-rc0
  options[:upsert] && !result ? {} : result
end

#no_timeoutQuery

Disable cursor timeout

Examples:

Disable cursor timeout.

db[:people].find.no_timeout

Returns:

Since:

  • 1.0.0



268
269
270
271
# File 'lib/moped/query.rb', line 268

def no_timeout
  operation.no_timeout = true
  self
end

#query_options(options) ⇒ Object



482
483
484
# File 'lib/moped/query.rb', line 482

def query_options(options)
  read_preference.query_options(options)
end

#read_preferenceObject



474
475
476
# File 'lib/moped/query.rb', line 474

def read_preference
  session.read_preference
end

#removeHash?

Remove a single document matching the query’s selector.

Examples:

Remove a single document.

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

Returns:

  • (Hash, nil)

    If in safe mode the last error result.

Since:

  • 1.0.0



323
324
325
326
327
328
329
330
331
332
333
# File 'lib/moped/query.rb', line 323

def remove
  cluster.with_primary do |node|
    node.remove(
      operation.database,
      operation.collection,
      operation.basic_selector,
      write_concern,
      flags: [ :remove_first ]
    )
  end
end

#remove_allHash?

Remove multiple documents matching the query’s selector.

Examples:

Remove all matching documents.

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

Returns:

  • (Hash, nil)

    If in safe mode the last error result.

Since:

  • 1.0.0



343
344
345
346
347
348
349
350
351
352
# File 'lib/moped/query.rb', line 343

def remove_all
  cluster.with_primary do |node|
    node.remove(
      operation.database,
      operation.collection,
      operation.basic_selector,
      write_concern
    )
  end
end

#select(select) ⇒ Query

Set the fields to include or exclude from the query.

Examples:

Select the fields to include or exclude.

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

Parameters:

  • select (Hash)

    The inclusions or exclusions.

Returns:

Since:

  • 1.0.0



364
365
366
367
# File 'lib/moped/query.rb', line 364

def select(select)
  operation.fields = select
  self
end

#skip(skip) ⇒ Query

Set the number of documents to skip.

Examples:

Set the number to skip.

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

Parameters:

  • skip (Integer)

    The number of documents to skip.

Returns:

Since:

  • 1.0.0



379
380
381
382
# File 'lib/moped/query.rb', line 379

def skip(skip)
  operation.skip = skip
  self
end

#sort(sort) ⇒ Query

Set the sort order for the query.

Examples:

Set the sort order.

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

Parameters:

  • sort (Hash)

    The order as key/(1/-1) pairs.

Returns:

Since:

  • 1.0.0



394
395
396
397
398
# File 'lib/moped/query.rb', line 394

def sort(sort)
  upgrade_to_advanced_selector
  operation.selector["$orderby"] = sort
  self
end

#tailableQuery

Tell the query to create a tailable cursor.

Examples:

Tell the query the cursor is tailable.

db[:people].find.tailable

Returns:

Since:

  • 1.3.0



408
409
410
411
# File 'lib/moped/query.rb', line 408

def tailable
  operation.flags.push(:tailable, :await_data)
  self
end

#update(change, flags = nil) ⇒ Hash?

Update a single document matching the query’s selector.

Examples:

Update the first matching document.

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

Parameters:

  • change (Hash)

    The changes to make to the document

  • flags (Array) (defaults to: nil)

    An array of operation flags. Valid values are: :multi and :upsert

Returns:

  • (Hash, nil)

    If in safe mode the last error result.

Since:

  • 1.0.0



425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/moped/query.rb', line 425

def update(change, flags = nil)
  cluster.with_primary do |node|
    node.update(
      operation.database,
      operation.collection,
      operation.selector["$query"] || operation.selector,
      change,
      write_concern,
      flags: flags
    )
  end
end

#update_all(change) ⇒ Hash?

Update multiple documents matching the query’s selector.

Examples:

Update multiple documents.

db[:people].find(name: "John").update_all("$set" => { name: "Mary" })

Parameters:

  • change (Hash)

    The changes to make to the documents

Returns:

  • (Hash, nil)

    If in safe mode the last error result.

Since:

  • 1.0.0



448
449
450
# File 'lib/moped/query.rb', line 448

def update_all(change)
  update(change, [ :multi ])
end

#upsert(change) ⇒ Hash?

Update an existing document with change, otherwise create one.

Examples:

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" }]

Parameters:

  • change (Hash)

    The changes to make to the the document.

Returns:

  • (Hash, nil)

    If in safe mode the last error result.

Since:

  • 1.0.0



466
467
468
# File 'lib/moped/query.rb', line 466

def upsert(change)
  update(change, [ :upsert ])
end

#write_concernObject



470
471
472
# File 'lib/moped/query.rb', line 470

def write_concern
  session.write_concern
end