Skip to content

Commit 9f42b50

Browse files
authored
DOCSP-45199: Cursors (#120)
* DOCSP-45199: Cursors * edits * fix link * JS feedback * tech review
1 parent 2f3d2cb commit 9f42b50

File tree

3 files changed

+252
-0
lines changed

3 files changed

+252
-0
lines changed

source/includes/read/cursors.rb

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
require 'bundler/inline'
2+
3+
gemfile do
4+
source 'https://rubygems.org'
5+
gem 'mongo'
6+
end
7+
8+
uri = '<connection string>'
9+
10+
Mongo::Client.new(uri) do |client|
11+
# start-db-coll
12+
database = client.use('sample_restaurants')
13+
collection = database[:restaurants]
14+
# end-db-coll
15+
16+
# Iterates over and prints all documents that have a "name" value of "Dunkin' Donuts"
17+
# start-cursor-iterate
18+
cursor = collection.find(name: "Dunkin' Donuts")
19+
cursor.each do |doc|
20+
puts doc
21+
end
22+
# end-cursor-iterate
23+
24+
# Retrieves and prints the first document stored in the cursor
25+
# start-cursor-first
26+
cursor = collection.find(name: "Dunkin' Donuts")
27+
first_doc = cursor.first
28+
puts first_doc
29+
# end-cursor-first
30+
31+
# Converts the documents stored in a cursor to an array
32+
# start-cursor-array
33+
cursor = collection.find(name: "Dunkin' Donuts")
34+
array_results = cursor.to_a
35+
# end-cursor-array
36+
37+
# Creates a collection with a maximum size and inserts documents representing vegetables
38+
# start-capped-coll
39+
db = client.use('db')
40+
collection = db[:vegetables, capped: true, size: 1024 * 1024]
41+
collection.create
42+
43+
vegetables = [
44+
{ name: 'cauliflower' },
45+
{ name: 'zucchini' }
46+
]
47+
48+
collection.insert_many(vegetables)
49+
# end-capped-coll
50+
51+
52+
# Iterates over the initial query results and continues iterating until three documents are stored in the cursor
53+
# by using a tailable cursor
54+
# start-tailable
55+
cursor = collection.find({}, cursor_type: :tailable)
56+
docs_found = 0
57+
58+
cursor.each do |doc|
59+
puts doc
60+
docs_found += 1
61+
break if docs_found >= 3
62+
end
63+
# end-tailable
64+
end

source/read.txt

+1
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ Read Data from MongoDB
2828
Specify Fields to Return </read/project>
2929
Distinct Field Values </read/distinct>
3030
Count Documents </read/count>
31+
Cursors </read/cursors>

source/read/cursors.txt

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
.. _ruby-cursors:
2+
3+
=========================
4+
Access Data From a Cursor
5+
=========================
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 1
11+
:class: singlecol
12+
13+
.. facet::
14+
:name: genre
15+
:values: reference
16+
17+
.. meta::
18+
:keywords: read, results, oplog
19+
20+
Overview
21+
--------
22+
23+
In this guide, you can learn how to access data from a **cursor** by using the
24+
{+driver-short+}.
25+
26+
A cursor is a mechanism that returns the results of a read operation in iterable
27+
batches. Because a cursor holds only a subset of documents at any given time,
28+
cursors reduce both memory consumption and the number of requests the driver sends to
29+
the server.
30+
31+
You cannot access the ``Mongo::Cursor`` class directly from your application code. When
32+
you use the {+driver-short+} to perform a read operation, the driver returns a
33+
``Mongo::Collection::View`` object that represents the query. Once you request
34+
query results from the ``Collection::View`` object, the driver internally stores
35+
these results in a ``Cursor`` object. Then, the ``Collection::View`` exposes
36+
the ``Enumerable`` interface, backed by the ``Cursor`` class, from
37+
which you can access the results.
38+
39+
Sample Data
40+
~~~~~~~~~~~
41+
42+
The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants``
43+
database from the :atlas:`Atlas sample datasets </sample-data>`. To access this collection
44+
from your {+language+} application, create a ``Mongo::Client`` object that connects to
45+
an Atlas cluster and assign the following values to your ``database`` and ``collection``
46+
variables:
47+
48+
.. literalinclude:: /includes/read/cursors.rb
49+
:language: ruby
50+
:dedent:
51+
:start-after: start-db-coll
52+
:end-before: end-db-coll
53+
54+
To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the
55+
:atlas:`Get Started with Atlas </getting-started>` guide.
56+
57+
.. _ruby-cursors-iterate:
58+
59+
Access Cursor Contents Iteratively
60+
----------------------------------
61+
62+
To iterate over the contents of a cursor, call the ``each`` method on the
63+
``Mongo::Collection::View`` object returned by the read operation. This instructs
64+
the driver to perform the operation and return each result stored in the
65+
``Mongo::Cursor``.
66+
67+
The following example uses the ``find`` method to retrieve all documents
68+
in which the ``name`` field value is ``"Dunkin' Donuts"``. It then prints
69+
each document stored in the cursor:
70+
71+
.. io-code-block::
72+
:copyable:
73+
74+
.. input:: /includes/read/cursors.rb
75+
:start-after: start-cursor-iterate
76+
:end-before: end-cursor-iterate
77+
:language: ruby
78+
:dedent:
79+
80+
.. output::
81+
:visible: false
82+
83+
{"_id"=>BSON::ObjectId('...'), ..., "name"=>"Dunkin' Donuts", "restaurant_id"=>"40363098"}
84+
{"_id"=>BSON::ObjectId('...'), ..., "name"=>"Dunkin' Donuts", "restaurant_id"=>"40379573"}
85+
{"_id"=>BSON::ObjectId('...'), ..., "name"=>"Dunkin' Donuts", "restaurant_id"=>"40392410"}
86+
...
87+
88+
Retrieve Documents Individually
89+
-------------------------------
90+
91+
To retrieve documents from a cursor individually, call the ``first`` method
92+
on the ``Mongo::Collection::View`` object returned by the read operation.
93+
94+
The following example finds all documents in a collection that have a ``name`` value
95+
of ``"Dunkin' Donuts"``. It then prints the first document in the cursor by calling the
96+
``first`` method.
97+
98+
.. io-code-block::
99+
:copyable:
100+
101+
.. input:: /includes/read/cursors.rb
102+
:start-after: start-cursor-first
103+
:end-before: end-cursor-first
104+
:language: ruby
105+
:dedent:
106+
107+
.. output::
108+
:visible: false
109+
110+
{"_id"=>BSON::ObjectId('...'), ..., "name"=>"Dunkin' Donuts", "restaurant_id"=>"40363098"}
111+
112+
Retrieve All Documents
113+
----------------------
114+
115+
.. warning::
116+
117+
If the number and size of documents returned by your query exceeds available
118+
application memory, your program will crash. If you expect a large result
119+
set, :ref:`access your cursor iteratively <ruby-cursors-iterate>`.
120+
121+
To retrieve all documents from a cursor, convert the cursor into an array by using
122+
the ``to_a`` method on its corresponding ``Mongo::Collection::View`` object.
123+
124+
The following example calls the ``to_a`` method to store the cursor results
125+
in an array:
126+
127+
.. literalinclude:: /includes/read/cursors.rb
128+
:language: ruby
129+
:dedent:
130+
:start-after: start-cursor-array
131+
:end-before: end-cursor-array
132+
133+
.. _ruby-tailable-cursor:
134+
135+
Tailable Cursors
136+
----------------
137+
138+
When querying on a :manual:`capped collection </core/capped-collections/>`, you
139+
can use a **tailable cursor** that remains open after the client exhausts the
140+
results in a cursor. To create a tailable cursor, pass the ``cursor_type`` option to
141+
the ``find`` method. Set this option to ``:tailable``.
142+
143+
For example, you can create a capped collection called ``vegetables``, as
144+
shown in the following code:
145+
146+
.. literalinclude:: /includes/read/cursors.rb
147+
:language: ruby
148+
:dedent:
149+
:start-after: start-capped-coll
150+
:end-before: end-capped-coll
151+
152+
Then, you can use the following code to retrieve all documents
153+
in the ``vegetables`` collection and store the results in a tailable
154+
cursor. After the cursor is exhausted, it remains open until
155+
retrieving three documents:
156+
157+
.. io-code-block::
158+
:copyable:
159+
160+
.. input:: /includes/read/cursors.rb
161+
:start-after: start-tailable
162+
:end-before: end-tailable
163+
:language: ruby
164+
:dedent:
165+
166+
.. output::
167+
:visible: false
168+
169+
{"_id"=>BSON::ObjectId('...'), "name"=>"cauliflower"}
170+
{"_id"=>BSON::ObjectId('...'), "name"=>"zucchini"}
171+
172+
If you insert another document into the ``vegetables`` collection, the preceding code prints
173+
the new document and does not retrieve more results from the cursor.
174+
175+
To learn more about tailable cursors, see :manual:`Tailable Cursors
176+
</core/tailable-cursors/>` in the {+mdb-server+} manual.
177+
178+
API Documentation
179+
-----------------
180+
181+
To learn more about any of the functions discussed in this guide, see the following API
182+
documentation:
183+
184+
- `Mongo::Cursor <{+api-root+}/Mongo/Cursor.html>`__
185+
- `Mongo::Collection::View <{+api-root+}/Mongo/Collection/View.html>`__
186+
- `find <{+api-root+}/Mongo/Collection.html#find-instance_method>`__
187+
- `each <{+api-root+}/Mongo/Cursor.html#each-instance_method>`__

0 commit comments

Comments
 (0)