Class: Mongo::Cursor

Inherits:
Object show all
Includes:
Enumerable, Conversions
Defined in:
lib/mongo/cursor.rb

Overview

A cursor over query results. Returned objects are hashes.

Constant Summary

Constants included from Conversions

Mongo::Conversions::ASCENDING_CONVERSION, Mongo::Conversions::DESCENDING_CONVERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Enumerable

#each_with_object

Methods included from Conversions

#array_as_sort_parameters, #sort_value, #string_as_sort_parameters

Constructor Details

#initialize(collection, opts = {}) ⇒ Cursor

Create a new cursor.

Note: cursors are created when executing queries using [Collection#find] and other similar methods. Application developers shouldn’t have to create cursors manually.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/mongo/cursor.rb', line 36

def initialize(collection, opts={})
  @cursor_id  = nil

  @db         = collection.db
  @collection = collection
  @connection = @db.connection
  @logger     = @connection.logger

  # Query selector
  @selector   = opts[:selector] || {}

  # Special operators that form part of $query
  @order      = opts[:order]
  @explain    = opts[:explain]
  @hint       = opts[:hint]
  @snapshot   = opts[:snapshot]
  @max_scan   = opts.fetch(:max_scan, nil)
  @return_key = opts.fetch(:return_key, nil)
  @show_disk_loc = opts.fetch(:show_disk_loc, nil)

  # Wire-protocol settings
  @fields     = convert_fields_for_query(opts[:fields])
  @skip       = opts[:skip]     || 0
  @limit      = opts[:limit]    || 0
  @tailable   = opts[:tailable] || false
  @timeout    = opts.fetch(:timeout, true)

  # Use this socket for the query
  @socket     = opts[:socket]

  @closed       = false
  @query_run    = false

  @transformer = opts[:transformer]
  batch_size(opts[:batch_size] || 0)

  @full_collection_name = "#{@collection.db.name}.#{@collection.name}"
  @cache        = []
  @returned     = 0

  if @collection.name =~ /^\$cmd/ || @collection.name =~ /^system/
    @command = true
  else
    @command = false
  end
end

Instance Attribute Details

#collectionObject (readonly)

Returns the value of attribute collection.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def collection
  @collection
end

#fieldsObject (readonly)

Returns the value of attribute fields.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def fields
  @fields
end

#full_collection_nameObject (readonly)

Returns the value of attribute full_collection_name.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def full_collection_name
  @full_collection_name
end

#hintObject (readonly)

Returns the value of attribute hint.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def hint
  @hint
end

#orderObject (readonly)

Returns the value of attribute order.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def order
  @order
end

#selectorObject (readonly)

Returns the value of attribute selector.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def selector
  @selector
end

#snapshotObject (readonly)

Returns the value of attribute snapshot.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def snapshot
  @snapshot
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def timeout
  @timeout
end

#transformerObject (readonly)

Returns the value of attribute transformer.



24
25
26
# File 'lib/mongo/cursor.rb', line 24

def transformer
  @transformer
end

Instance Method Details

#batch_size(size = 0) ⇒ Cursor

Set the batch size for server responses.

Note that the batch size will take effect only on queries where the number to be returned is greater than 100.

Parameters:

  • size (Integer) (defaults to: 0)

    either 0 or some integer greater than 1. If 0, the server will determine the batch size.

Returns:



223
224
225
226
227
228
229
230
231
232
# File 'lib/mongo/cursor.rb', line 223

def batch_size(size=0)
  check_modifiable
  if size < 0 || size == 1
    raise ArgumentError, "Invalid value for batch_size #{size}; must be 0 or > 1."
  else
    @batch_size = size > @limit ? @limit : size
  end

  self
end

#closeTrue

Close the cursor.

Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to close it manually.

Note also: Collection#find takes an optional block argument which can be used to ensure that your cursors get closed.

Returns:

  • (True)


293
294
295
296
297
298
299
300
301
302
303
# File 'lib/mongo/cursor.rb', line 293

def close
  if @cursor_id && @cursor_id != 0
    message = BSON::ByteBuffer.new([0, 0, 0, 0])
    message.put_int(1)
    message.put_long(@cursor_id)
    @logger.debug("MONGODB cursor.close #{@cursor_id}") if @logger
    @connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, :connection => :reader)
  end
  @cursor_id = 0
  @closed    = true
end

#closed?Boolean

Is this cursor closed?

Returns:

  • (Boolean)


308
# File 'lib/mongo/cursor.rb', line 308

def closed?; @closed; end

#count(skip_and_limit = false) ⇒ Integer

Get the size of the result set for this query.

Parameters:

  • whether (Boolean)

    of not to take notice of skip and limit

Returns:

  • (Integer)

    the number of objects in the result set for this query.

Raises:



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/mongo/cursor.rb', line 138

def count(skip_and_limit = false)
  command = BSON::OrderedHash["count",  @collection.name, "query",  @selector]

  if skip_and_limit
    command.merge!(BSON::OrderedHash["limit", @limit]) if @limit != 0
    command.merge!(BSON::OrderedHash["skip", @skip]) if @skip != 0
  end

  command.merge!(BSON::OrderedHash["fields", @fields])

  response = @db.command(command)
  return response['n'].to_i if Mongo::Support.ok?(response)
  return 0 if response['errmsg'] == "ns missing"
  raise OperationFailure, "Count failed: #{response['errmsg']}"
end

#each { ... } ⇒ Object

Iterate over each document in this cursor, yielding it to the given block.

Iterating over an entire cursor will close it.

Examples:

if ‘comments’ represents a collection of comments:

comments.find.each do |doc|
  puts doc['user']
end

Yields:

  • passes each document to a block for processing.



245
246
247
248
249
250
251
252
# File 'lib/mongo/cursor.rb', line 245

def each
  #num_returned = 0
  #while has_next? && (@limit <= 0 || num_returned < @limit)
  while doc = next_document
    yield doc #next_document
    #num_returned += 1
  end
end

#explainHash

Get the explain plan for this cursor.

Returns:

  • (Hash)

    a document containing the explain plan for this cursor.



275
276
277
278
279
280
281
# File 'lib/mongo/cursor.rb', line 275

def explain
  c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true))
  explanation = c.next_document
  c.close

  explanation
end

#has_next?Boolean

Determine whether this cursor has any remaining results.

Returns:

  • (Boolean)


127
128
129
# File 'lib/mongo/cursor.rb', line 127

def has_next?
  num_remaining > 0
end

#inspectObject

Clean output for inspect.



342
343
344
345
# File 'lib/mongo/cursor.rb', line 342

def inspect
  "<Mongo::Cursor:0x#{object_id.to_s(16)} namespace='#{@db.name}.#{@collection.name}' " +
    "@selector=#{@selector.inspect}>"
end

#limit(number_to_return = nil) ⇒ Integer

Limit the number of results to be returned by this cursor.

This method overrides any limit specified in the Collection#find method, and only the last limit applied has an effect.

Returns:

  • (Integer)

    the current number_to_return if no parameter is given.

Raises:



189
190
191
192
193
194
195
# File 'lib/mongo/cursor.rb', line 189

def limit(number_to_return=nil)
  return @limit unless number_to_return
  check_modifiable

  @limit = number_to_return
  self
end

#next_documentHash, Nil Also known as: next

Get the next document specified the cursor options.

Returns:

  • (Hash, Nil)

    the next document or Nil if no documents remain.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/mongo/cursor.rb', line 86

def next_document
  refresh if @cache.length == 0
  doc = @cache.shift

  if doc && doc['$err']
    err = doc['$err']

    # If the server has stopped being the master (e.g., it's one of a
    # pair but it has died or something like that) then we close that
    # connection. The next request will re-open on master server.
    if err == "not master"
      @connection.close
      raise ConnectionFailure, err
    end

    raise OperationFailure, err
  end

  if @transformer.nil?
    doc
  else
    @transformer.call(doc) if doc
  end
end

#query_options_hashHash

Get the query options for this Cursor.

Returns:



327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/mongo/cursor.rb', line 327

def query_options_hash
  { :selector => @selector,
    :fields   => @fields,
    :skip     => @skip,
    :limit    => @limit,
    :order    => @order,
    :hint     => @hint,
    :snapshot => @snapshot,
    :timeout  => @timeout,
    :max_scan => @max_scan,
    :return_key => @return_key,
    :show_disk_loc => @show_disk_loc }
end

#query_optsInteger

Returns an integer indicating which query options have been selected.

The MongoDB wire protocol.



316
317
318
319
320
321
322
# File 'lib/mongo/cursor.rb', line 316

def query_opts
  opts     = 0
  opts    |= Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT unless @timeout
  opts    |= Mongo::Constants::OP_QUERY_SLAVE_OK if @connection.slave_ok?
  opts    |= Mongo::Constants::OP_QUERY_TAILABLE if @tailable
  opts
end

#rewind!Object

Reset this cursor on the server. Cursor options, such as the query string and the values for skip and limit, are preserved.



114
115
116
117
118
119
120
121
122
# File 'lib/mongo/cursor.rb', line 114

def rewind!
  close
  @cache.clear
  @cursor_id  = nil
  @closed     = false
  @query_run  = false
  @n_received = nil
  true
end

#skip(number_to_skip = nil) ⇒ Integer

Skips the first number_to_skip results of this cursor. Returns the current number_to_skip if no parameter is given.

This method overrides any skip specified in the Collection#find method, and only the last skip applied has an effect.

Returns:

  • (Integer)

Raises:



206
207
208
209
210
211
212
# File 'lib/mongo/cursor.rb', line 206

def skip(number_to_skip=nil)
  return @skip unless number_to_skip
  check_modifiable

  @skip = number_to_skip
  self
end

#sort(key_or_list, direction = nil) ⇒ Object

Sort this cursor’s results.

This method overrides any sort order specified in the Collection#find method, and only the last sort applied has an effect.

Parameters:

  • key_or_list (Symbol, Array)

    either 1) a key to sort by or 2) an array of [key, direction] pairs to sort by. Direction should be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)

Raises:



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/mongo/cursor.rb', line 166

def sort(key_or_list, direction=nil)
  check_modifiable

  if !direction.nil?
    order = [[key_or_list, direction]]
  else
    order = key_or_list
  end

  @order = order
  self
end

#to_aArray

Receive all the documents from this cursor as an array of hashes.

Notes:

If you’ve already started iterating over the cursor, the array returned by this method contains only the remaining documents. See Cursor#rewind! if you need to reset the cursor.

Use of this method is discouraged - in most cases, it’s much more efficient to retrieve documents as you need them by iterating over the cursor.

Returns:

  • (Array)

    an array of documents.



266
267
268
# File 'lib/mongo/cursor.rb', line 266

def to_a
  super
end