Skip to content

Commit 285e605

Browse files
rustagirnorareidy
andauthored
DOCSP-30537: cursor fundamentals (#28)
Co-authored-by: norareidy <[email protected]>
1 parent 514ba1b commit 285e605

File tree

4 files changed

+377
-3
lines changed

4 files changed

+377
-3
lines changed

source/fundamentals/crud/read-operations.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ Read Operations
99

1010
/fundamentals/crud/read-operations/retrieve
1111
/fundamentals/crud/read-operations/query
12+
/fundamentals/crud/read-operations/cursor
1213

1314
..
1415
/fundamentals/crud/read-operations/count
15-
/fundamentals/crud/read-operations/cursor
1616
/fundamentals/crud/read-operations/distinct
1717
/fundamentals/crud/read-operations/sort
1818
/fundamentals/crud/read-operations/skip
@@ -24,10 +24,10 @@ Read Operations
2424

2525
- :ref:`rust-query-guide`
2626
- :ref:`rust-retrieve-guide`
27+
- :ref:`rust-cursor-guide`
2728

2829
.. - :ref:`rust-query-guide`
2930
.. - :ref:`rust-count-guide`
30-
.. - :ref:`rust-cursor-guide`
3131
.. - :ref:`rust-distinct-guide`
3232
.. - :ref:`rust-sort-guide`
3333
.. - :ref:`rust-skip-guide`
Lines changed: 312 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,312 @@
1-
.. _rust-cursor-guide:
1+
.. _rust-cursor-guide:
2+
3+
=============================
4+
Access Data by Using a Cursor
5+
=============================
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 2
11+
:class: singlecol
12+
13+
Overview
14+
--------
15+
16+
In this guide, you can learn how to use the {+driver-short+} to access
17+
data returned from a read operation or aggregation by using a **cursor**. A
18+
cursor is a mechanism that enables you to iterate through multiple documents
19+
while holding only a subset of them in memory at a given time.
20+
21+
The driver offers the ``Cursor`` type to retrieve documents from a cursor.
22+
For example, when you run a find operation that can return multiple
23+
documents, the driver returns a ``Cursor`` instance from which you can access
24+
the matched documents.
25+
26+
After you run a read operation or aggregation, the returned ``Cursor`` instance
27+
contains the first batch of results from the operation. As you iterate through
28+
the cursor, the server returns more individual results. If there are more
29+
matching documents after you reach the end of a batch of results, the ``Cursor``
30+
instance fetches the next batch of documents until all the results are returned.
31+
32+
This guide includes the following sections:
33+
34+
- :ref:`Retrieve Documents Individually <rust-cursor-individual>`:
35+
describes how to use iteration or a stream to access results one at a time
36+
37+
- :ref:`Retrieve Documents as an Array <rust-cursor-array>`:
38+
describes how to access all results as a single array by collecting the
39+
returned cursor results
40+
41+
- :ref:`Specify Cursor Behavior <rust-cursor-options>`: describes how
42+
to configure the cursor that a method returns
43+
44+
- :ref:`Additional Information <rust-cursor-addtl-info>`:
45+
provides links to related topics and API documentation for types
46+
and methods mentioned in this guide
47+
48+
.. _rust-cursor-individual:
49+
50+
Retrieve Documents Individually
51+
-------------------------------
52+
53+
The driver provides the following access patterns to iterate through
54+
documents returned by a ``Cursor`` instance:
55+
56+
- :ref:`Built-in Pattern <rust-cursor-indiv-builtin>`: advance the cursor,
57+
then retrieve and deserialize the current document
58+
- :ref:`Stream Implementation Pattern <rust-cursor-indiv-stream>`: iterate over
59+
the cursor and call methods provided by ``Stream`` to process single
60+
or multiple documents
61+
62+
The following sections describe these access patterns and corresponding
63+
methods in more detail.
64+
65+
.. _rust-cursor-indiv-builtin:
66+
67+
Built-in Pattern
68+
~~~~~~~~~~~~~~~~
69+
70+
You can use the driver's built-in access pattern to retrieve and process
71+
documents one by one.
72+
73+
The ``Cursor`` type includes the ``advance()`` and
74+
``deserialize_current()`` methods to iterate through a cursor and
75+
access documents individually.
76+
77+
The ``advance()`` method moves the cursor forward and sends a request to the
78+
database for more results when the local buffer is exhausted, which occurs
79+
when the cursor reaches the end of a batch of results. Each time the cursor
80+
reaches the end of a batch of results, it requests the next batch. The cursor
81+
is exhausted when it has no more matching documents to return and is no longer
82+
usable. The ``advance()`` method returns a ``true`` result if new results are
83+
successfully returned and a ``false`` result if the cursor is closed.
84+
85+
The ``deserialize_current()`` method returns a reference to the current
86+
result in the cursor and deserializes the result into the type
87+
associated with the cursor. Unless you specify a type, the method uses the
88+
same type that your collection is parameterized with.
89+
90+
.. important::
91+
92+
You can only call the ``deserialize_current()`` method if the ``advance()``
93+
method returns a ``true`` result. The driver generates an error if you call
94+
``deserialize_current()`` on the cursor without a ``true`` result or
95+
without calling previously calling ``advance()``.
96+
97+
The following example shows how to implement this access pattern to
98+
iterate through the results of a find operation on the ``fruits``
99+
collection:
100+
101+
.. io-code-block::
102+
:copyable: true
103+
104+
.. input:: /includes/fundamentals/code-snippets/crud/cursor.rs
105+
:start-after: start-indiv-builtin
106+
:end-before: end-indiv-builtin
107+
:language: rust
108+
:dedent:
109+
110+
.. output::
111+
:language: console
112+
:visible: false
113+
114+
Document({"_id": ObjectId("..."), "name": String("strawberry"), "color": String("red")})
115+
Document({"_id": ObjectId("..."), "name": String("pomegranate"), "color": String("red")})
116+
117+
.. _rust-cursor-indiv-stream:
118+
119+
Stream Implementation Pattern
120+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
121+
122+
You can access cursor results as a stream to retrieve individual documents
123+
or collect multiple documents at once.
124+
125+
The ``Cursor`` type implements the ``Stream`` trait, so you can iterate
126+
through the cursor as a stream. This pattern may help you write more
127+
concise code than the built-in pattern, since the ``Stream`` extension trait
128+
``StreamExt`` provides numerous functions to combine operations and
129+
consolidate code.
130+
131+
You can use the following methods to use the stream pattern:
132+
133+
- ``next()``: advances the cursor to the next result and returns an
134+
``Option<Result<T>>`` type
135+
- ``try_next()``: advances the cursor to the next result and returns
136+
a ``Result<Option<T>>`` type
137+
138+
.. important:: Required Imports for Stream Pattern Methods
139+
140+
To use the ``next()`` method, you must import the ``StreamExt``
141+
trait. To use the ``try_next()`` method, you must import the
142+
``TryStreamExt`` trait.
143+
144+
The following example shows how to implement the two stream methods to
145+
iterate through the results of find operations on the ``fruits``
146+
collection:
147+
148+
.. io-code-block::
149+
:copyable: true
150+
151+
.. input:: /includes/fundamentals/code-snippets/crud/cursor.rs
152+
:start-after: start-indiv-stream
153+
:end-before: end-indiv-stream
154+
:language: rust
155+
:dedent:
156+
157+
.. output::
158+
:language: console
159+
:visible: false
160+
161+
Output from next() iteration:
162+
{ "_id": ObjectId("..."), "name": "strawberry", "color": "red" }
163+
{ "_id": ObjectId("..."), "name": "pomegranate", "color": "red" }
164+
165+
Output from try_next() iteration:
166+
{ "_id": ObjectId("..."), "name": "banana", "color": "yellow" }
167+
{ "_id": ObjectId("..."), "name": "pineapple", "color": "yellow" }
168+
169+
.. _rust-cursor-array:
170+
171+
Retrieve Documents as an Array
172+
------------------------------
173+
174+
Because the ``Cursor`` type implements the ``Stream`` trait, you can
175+
collect the results from a cursor into an array.
176+
177+
You can use the following methods to retrieve documents as an array:
178+
179+
- ``collect()``: collects results from a cursor into a
180+
``Vec<Result<T>>`` type
181+
- ``try_collect()``: collects results from a cursor into a
182+
``Result<Vec<T>>`` type
183+
184+
.. note::
185+
186+
To use the ``collect()`` method, you must import the ``StreamExt``
187+
trait. To use the ``try_collect()`` method, you must import the
188+
``TryStreamExt`` trait.
189+
190+
.. io-code-block::
191+
:copyable: true
192+
193+
.. input:: /includes/fundamentals/code-snippets/crud/cursor.rs
194+
:start-after: start-array
195+
:end-before: end-array
196+
:language: rust
197+
:dedent:
198+
199+
.. output::
200+
:language: console
201+
:visible: false
202+
203+
Output from collect():
204+
[Ok(Document({"_id": ObjectId("..."), "name": String("strawberry"), "color": String("red")})), Ok(Document({"_id": ObjectId("..."), "name": String("pomegranate"), "color": String("red")}))]
205+
206+
Output from try_collect():
207+
[Document({"_id": ObjectId("..."), "name": String("banana"), "color": String("yellow")}), Document({"_id": ObjectId("..."), "name": String("pineapple"), "color": String("yellow")})]
208+
209+
.. warning:: Avoid Exceeding Application Memory Limits
210+
211+
Avoid converting large sets of results to arrays. If the array exceeds
212+
the size of available application memory, your application might crash.
213+
If you expect a large result set, retrieve documents from the cursor individually.
214+
To learn how to iterate through the cursor, see the :ref:`Retrieve Documents Individually
215+
<rust-cursor-individual>` section of this guide.
216+
217+
.. _rust-cursor-options:
218+
219+
Specify Cursor Behavior
220+
-----------------------
221+
222+
To modify the cursor that an operation returns, pass options to
223+
the method that returns the ``Cursor`` instance. For example, you can
224+
specify cursor-related options in a ``FindOptions`` type that you pass to the
225+
``find()`` method.
226+
227+
The following table describes cursor-related options that you can set in
228+
an options instance:
229+
230+
.. list-table::
231+
:widths: 30 70
232+
:header-rows: 1
233+
234+
* - Setting
235+
- Description
236+
237+
* - ``batch_size``
238+
- | Specifies the maximum number of documents the server returns per
239+
cursor batch. This option sets the number of documents the cursor
240+
keeps in memory rather than the number of documents the cursor
241+
returns.
242+
243+
| Type: ``u32``
244+
| Default: ``101`` documents initially, ``16 MB`` maximum for
245+
subsequent batches
246+
247+
* - ``cursor_type``
248+
- | Specifies the type of cursor to return. You can set this option
249+
to produce a tailable cursor. To learn more about tailable
250+
cursors, see :manual:`Tailable Cursors
251+
</core/tailable-cursors/>` in the Server manual.
252+
253+
| Type: ``CursorType``
254+
| Default: ``CursorType::NonTailable``
255+
256+
* - ``no_cursor_timeout``
257+
- | Specifies whether the server closes the cursor after a period
258+
of inactivity.
259+
260+
.. important::
261+
262+
Because the ``Cursor`` type implements the ``Drop`` trait, the
263+
server closes a cursor when it goes out of scope. The server
264+
runs an asynchronous ``killCursors`` command to close the
265+
cursor. See :manual:`killCursors </reference/command/killCursors/>`
266+
in the Server manual to learn more.
267+
268+
| Type: ``bool``
269+
| Default: ``false``
270+
271+
The following code shows how to construct a ``FindOptions``
272+
instance and specify cursor-related settings:
273+
274+
.. literalinclude:: /includes/fundamentals/code-snippets/crud/cursor.rs
275+
:start-after: start-options
276+
:end-before: end-options
277+
:language: rust
278+
:copyable:
279+
:dedent:
280+
281+
.. _rust-cursor-addtl-info:
282+
283+
Additional Information
284+
----------------------
285+
286+
To learn more about the operations in this guide, see the
287+
following Rust driver reference documentation:
288+
289+
- :ref:`rust-retrieve-guide`
290+
- :ref:`rust-query-guide`
291+
292+
.. TODO link to serialization guide
293+
294+
API Documentation
295+
~~~~~~~~~~~~~~~~~
296+
297+
To learn more about the methods and types mentioned in this
298+
guide, see the following API documentation:
299+
300+
- `Cursor <{+api+}/struct.Cursor.html>`__
301+
- `advance() <{+api+}/struct.Cursor.html#method.advance>`__
302+
- `deserialize_current() <{+api+}/struct.Cursor.html#method.deserialize_current>`__
303+
- `next() <https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.next>`__ in the
304+
``StreamExt`` trait
305+
- `try_next() <https://docs.rs/futures/latest/futures/stream/trait.TryStreamExt.html#method.try_next>`__ in the
306+
``TryStreamExt`` trait
307+
- `collect() <https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.collect>`__ in the
308+
``StreamExt`` trait
309+
- `try_collect() <https://docs.rs/futures/latest/futures/stream/trait.TryStreamExt.html#method.try_collect>`__ in the
310+
``TryStreamExt`` trait
311+
- `find() <{+api+}/struct.Collection.html#method.find>`__
312+
- `FindOptions <{+api+}/options/struct.FindOptions.html>`__

source/fundamentals/crud/read-operations/retrieve.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ following parameters:
197197
``unit_price`` in descending order
198198

199199
.. io-code-block::
200+
:copyable: true
200201

201202
.. input:: /includes/fundamentals/code-snippets/crud/retrieve.rs
202203
:start-after: begin-find-many
@@ -234,6 +235,7 @@ following parameters:
234235
- A ``FindOneOptions`` instance that skips the first two matched documents
235236

236237
.. io-code-block::
238+
:copyable: true
237239

238240
.. input:: /includes/fundamentals/code-snippets/crud/retrieve.rs
239241
:start-after: begin-find-one
@@ -348,6 +350,7 @@ pipeline that contains the following stages:
348350
- A ``$sort`` stage to by ``avg_price`` in ascending order
349351

350352
.. io-code-block::
353+
:copyable: true
351354

352355
.. input:: /includes/fundamentals/code-snippets/crud/retrieve.rs
353356
:start-after: begin-agg

0 commit comments

Comments
 (0)