Class: Mongo::Cursor Private

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable, Retryable
Defined in:
build/ruby-driver-master/lib/mongo/cursor.rb,
build/ruby-driver-master/lib/mongo/cursor/kill_spec.rb

Overview

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

Client-side representation of an iterator over a query result set on the server.

Cursor objects are not directly exposed to application code. Rather, Collection::View exposes the Enumerable interface to the applications, and the enumerator is backed by a Cursor instance.

Examples:

Get an array of 5 users named Emily.

users.find({:name => 'Emily'}).limit(5).to_a

Call a block on each user doc.

users.find.each { |doc| puts doc }

Direct Known Subclasses

CachingCursor

Defined Under Namespace

Classes: KillSpec

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Retryable

#legacy_write_with_retry, #nro_write_with_retry, #read_with_one_retry, #read_with_retry, #read_with_retry_cursor, #write_with_retry

Constructor Details

#initialize(view, result, server, options = {}) ⇒ Cursor

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.

Creates a Cursor object.

Examples:

Instantiate the cursor.

Mongo::Cursor.new(view, response, server)

Parameters:

  • view (CollectionView)

    The CollectionView defining the query.

  • result (Operation::Result)

    The result of the first execution.

  • server (Server)

    The server this cursor is locked to.

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

    The cursor options.

Options Hash (options):

  • :disable_retry (true, false)

    Whether to disable retrying on error when sending getMore operations (deprecated, getMore operations are no longer retried)

  • :retry_reads (true, false)

    Retry reads (following the modern mechanism), default is true

Since:

  • 2.0.0



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 69

def initialize(view, result, server, options = {})
  unless result.is_a?(Operation::Result)
    raise ArgumentError, "Second argument must be a Mongo::Operation::Result: #{result.inspect}"
  end

  @view = view
  @server = server
  @initial_result = result
  @namespace = result.namespace
  @remaining = limit if limited?
  @cursor_id = result.cursor_id
  if @cursor_id.nil?
    raise ArgumentError, 'Cursor id must be present in the result'
  end
  @options = options
  @session = @options[:session]
  unless closed?
    register
    ObjectSpace.define_finalizer(self, self.class.finalize(kill_spec,
      cluster,
      server,
      @session))
  end
end

Instance Attribute Details

#initial_resultObject (readonly)

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.



98
99
100
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 98

def initial_result
  @initial_result
end

#resume_tokenBSON::Document | nil (readonly)

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.

The resume token tracked by the cursor for change stream resuming

Returns:

  • (BSON::Document | nil)

    The cursor resume token.



50
51
52
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 50

def resume_token
  @resume_token
end

#serverObject (readonly)

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.



95
96
97
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 95

def server
  @server
end

#viewCollection::View (readonly)

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.

Returns view The collection view.

Returns:



44
45
46
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 44

def view
  @view
end

Class Method Details

.finalize(kill_spec, cluster, server, session) ⇒ Proc

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.

Finalize the cursor for garbage collection. Schedules this cursor to be included in a killCursors operation executed by the Cluster's CursorReaper.

Parameters:

  • kill_spec (Cursor::KillSpec)

    The KillCursor operation specification.

  • cluster (Mongo::Cluster)

    The cluster associated with this cursor and its server.

  • server (Mongo::Server)

    The server to send the killCursors operation to.

Returns:

  • (Proc)

    The Finalizer.



110
111
112
113
114
115
116
117
118
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 110

def self.finalize(kill_spec, cluster, server, session)
  unless KillSpec === kill_spec
    raise ArgumentError, "First argument must be a KillSpec: #{kill_spec.inspect}"
  end
  proc do
    cluster.schedule_kill_cursor(kill_spec, server)
    session.end_session if session && session.implicit?
  end
end

Instance Method Details

#batch_sizeInteger

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.

Get the batch size.

Examples:

Get the batch size.

cursor.batch_size

Returns:

  • (Integer)

    The batch size.

Since:

  • 2.2.0



256
257
258
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 256

def batch_size
  @view.batch_size && @view.batch_size > 0 ? @view.batch_size : limit
end

#closenil

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.

Closes this cursor, freeing any associated resources on the client and the server.

Returns:

  • (nil)

    Always nil.

Raises:



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 280

def close
  return if closed?

  unregister
  read_with_one_retry do
    spec = {
      coll_name: collection_name,
      db_name: database.name,
      cursor_ids: [id],
    }
    op = Operation::KillCursors.new(spec)
    execute_operation(op)
  end

  nil
ensure
  end_session
  @cursor_id = 0
end

#closed?true, false

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.

Is the cursor closed?

Examples:

Is the cursor closed?

cursor.closed?

Returns:

  • (true, false)

    If the cursor is closed.

Since:

  • 2.2.0



268
269
270
271
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 268

def closed?
  # @cursor_id should in principle never be nil
  @cursor_id.nil? || @cursor_id == 0
end

#collection_nameString

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.

Get the parsed collection name.

Examples:

Get the parsed collection name.

cursor.coll_name

Returns:

  • (String)

    The collection name.

Since:

  • 2.2.0



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 308

def collection_name
  # In most cases, this will be equivalent to the name of the collection
  # object in the driver. However, in some cases (e.g. when connected
  # to an Atlas Data Lake), the namespace returned by the find command
  # may be different, which is why we want to use the collection name based
  # on the namespace in the command result.
  if @namespace
    # Often, the namespace will be in the format "database.collection".
    # However, sometimes the collection name will contain periods, which
    # is why this method joins all the namespace components after the first.
    ns_components = @namespace.split('.')
    ns_components[1...ns_components.length].join('.')
  else
    collection.name
  end
end

#eachEnumerator

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.

Iterate through documents returned from the query.

A cursor may be iterated at most once. Incomplete iteration is also allowed. Attempting to iterate the cursor more than once raises InvalidCursorOperation.

Examples:

Iterate over the documents in the cursor.

cursor.each do |doc|
  ...
end

Returns:

  • (Enumerator)

    The enumerator.

Since:

  • 2.0.0



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 146

def each

  # If we already iterated past the first batch (i.e., called get_more
  # at least once), the cursor on the server side has advanced past
  # the first batch and restarting iteration from the beginning by
  # returning initial result would miss documents in the second batch
  # and subsequent batches up to wherever the cursor is. Detect this
  # condition and abort the iteration.
  #
  # In a future driver version, each would either continue from the
  # end of previous iteration or would always restart from the
  # beginning.
  if @get_more_called
    raise Error::InvalidCursorOperation, 'Cannot restart iteration of a cursor which issued a getMore'
  end

  # To maintain compatibility with pre-2.10 driver versions, reset
  # the documents array each time a new iteration is started.
  @documents = nil

  if block_given?
    # StopIteration raised by try_next ends this loop.
    loop do
      document = try_next
      yield document if document
    end
    self
  else
    documents = []
    # StopIteration raised by try_next ends this loop.
    loop do
      document = try_next
      documents << document if document
    end
    documents
  end
end

#fully_iterated?Boolean

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.

Returns:

  • (Boolean)


380
381
382
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 380

def fully_iterated?
  !!@fully_iterated
end

#get_moreArray<BSON::Document>

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.

Execute a getMore command and return the batch of documents obtained from the server.

Returns:

  • (Array<BSON::Document>)

    The batch of documents



358
359
360
361
362
363
364
365
366
367
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 358

def get_more
  @get_more_called = true

  # Modern retryable reads specification prohibits retrying getMores.
  # Legacy retryable read logic used to retry getMores, but since
  # doing so may result in silent data loss, the driver no longer retries
  # getMore operations in any circumstance.
  # https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.rst#qa
  process(execute_operation(get_more_operation))
end

#idInteger

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.

Note:

A cursor id of 0 means the cursor was closed on the server.

Get the cursor id.

Examples:

Get the cursor id.

cursor.id

Returns:

  • (Integer)

    The cursor id.

Since:

  • 2.2.0



335
336
337
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 335

def id
  @cursor_id
end

#inspectString

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.

Get a human-readable string representation of Cursor.

Examples:

Inspect the cursor.

cursor.inspect

Returns:

  • (String)

    A string representation of a Cursor instance.

Since:

  • 2.0.0



128
129
130
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 128

def inspect
  "#<Mongo::Cursor:0x#{object_id} @view=#{@view.inspect}>"
end

#kill_specObject

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.



370
371
372
373
374
375
376
377
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 370

def kill_spec
  KillSpec.new(
    cursor_id: id,
    coll_name: collection_name,
    db_name: database.name,
    service_id: initial_result.connection_description.service_id,
  )
end

#to_returnInteger

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.

Get the number of documents to return. Used on 3.0 and lower server versions.

Examples:

Get the number to return.

cursor.to_return

Returns:

  • (Integer)

    The number of documents to return.

Since:

  • 2.2.0



348
349
350
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 348

def to_return
  use_limit? ? @remaining : (batch_size || 0)
end

#try_nextBSON::Document | nil

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.

Note:

This method is experimental and subject to change.

Return one document from the query, if one is available.

This method will wait up to max_await_time_ms milliseconds for changes from the server, and if no changes are received it will return nil. If there are no more documents to return from the server, or if we have exhausted the cursor, it will raise a StopIteration exception.

Returns:

  • (BSON::Document | nil)

    A document.

Raises:

  • (StopIteration)

    Raised on the calls after the cursor had been completely iterated.



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'build/ruby-driver-master/lib/mongo/cursor.rb', line 200

def try_next
  if @documents.nil?
    # Since published versions of Mongoid have a copy of old driver cursor
    # code, our dup call in #process isn't invoked when Mongoid query
    # cache is active. Work around that by also calling dup here on
    # the result of #process which might come out of Mongoid's code.
    @documents = process(@initial_result).dup
    # the documents here can be an empty array, hence
    # we may end up issuing a getMore in the first try_next call
  end

  if @documents.empty?
    # On empty batches, we cache the batch resume token
    cache_batch_resume_token

    unless closed?
      if exhausted?
        close
        @fully_iterated = true
        raise StopIteration
      end
      @documents = get_more
    else
      @fully_iterated = true
      raise StopIteration
    end
  else
    # cursor is closed here
    # keep documents as an empty array
  end

  # If there is at least one document, cache its _id
  if @documents[0]
    cache_resume_token(@documents[0])
  end

  # Cache the batch resume token if we are iterating
  # over the last document, or if the batch is empty
  if @documents.size <= 1
    cache_batch_resume_token
    if closed?
      @fully_iterated = true
    end
  end

  return @documents.shift
end