Skip to content

Commit dae52bf

Browse files
authored
DOCSP-49067: Cursors (#584)
1 parent 3f2c2ae commit dae52bf

File tree

2 files changed

+334
-0
lines changed

2 files changed

+334
-0
lines changed

source/crud/query/cursors.txt

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
.. _csharp-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 tool 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 network bandwidth usage.
29+
30+
You can retrieve a cursor by using the ``FindSync()`` or ``FindAsync()`` method. You can
31+
also convert the results of the ``Find()`` method to a cursor by chaining the ``ToCursor()``
32+
or ``ToCursorAsync()`` method.
33+
34+
Sample Data
35+
~~~~~~~~~~~
36+
37+
The examples in this guide use the ``restaurants`` collection
38+
in the ``sample_restaurants`` database provided in the :atlas:`Atlas sample datasets </sample-data>`.
39+
To learn how to create a free MongoDB Atlas cluster and load the sample datasets,
40+
see the :ref:`<csharp-get-started>` tutorial.
41+
42+
The examples on this page use the following ``Restaurant`` object to model the documents
43+
in the ``restaurants`` collection:
44+
45+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
46+
:start-after: start-restaurant-class
47+
:end-before: end-restaurant-class
48+
:language: csharp
49+
50+
.. _csharp-cursors-iterate:
51+
52+
Access Cursor Contents Iteratively
53+
----------------------------------
54+
55+
To iterate over the contents of a cursor, use a ``foreach`` loop inside a ``using`` block.
56+
The following example retrieves documents from the ``restaurants`` collection in which the
57+
value of the ``name`` field is ``"Starbucks"``, then iterates over the results.
58+
Select the :guilabel:`Synchronous` or :guilabel:`Asynchronous` tab to see the corresponding
59+
code:
60+
61+
.. tabs::
62+
63+
.. tab:: Synchronous
64+
:tabid: sync
65+
66+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
67+
:start-after: start-cursor-iterate
68+
:end-before: end-cursor-iterate
69+
:language: csharp
70+
:dedent:
71+
72+
.. tab:: Asynchronous
73+
:tabid: async
74+
75+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
76+
:start-after: start-cursor-iterate-async
77+
:end-before: end-cursor-iterate-async
78+
:language: csharp
79+
:dedent:
80+
81+
The following example performs the same operation but uses the ``ToCursor()`` method.
82+
Select the :guilabel:`Synchronous` or :guilabel:`Asynchronous`
83+
tab to see the corresponding code:
84+
85+
.. tabs::
86+
87+
.. tab:: Synchronous
88+
:tabid: sync
89+
90+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
91+
:start-after: start-cursor-iterate-to-cursor
92+
:end-before: end-cursor-iterate-to-cursor
93+
:language: csharp
94+
:dedent:
95+
96+
.. tab:: Asynchronous
97+
:tabid: async
98+
99+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
100+
:start-after: start-cursor-iterate-to-cursor-async
101+
:end-before: end-cursor-iterate-to-cursor-async
102+
:language: csharp
103+
:dedent:
104+
105+
Retrieve All Documents
106+
----------------------
107+
108+
.. warning::
109+
110+
If the number and size of documents returned by your query exceeds available
111+
application memory, your program might crash. If you expect a large result
112+
set, :ref:`access your cursor iteratively <csharp-cursors-iterate>`.
113+
114+
To retrieve all documents from a cursor, use the ``ToList()`` method, as shown in the
115+
following example. Select the :guilabel:`Synchronous` or :guilabel:`Asynchronous`
116+
tab to see the corresponding code:
117+
118+
.. tabs::
119+
120+
.. tab:: Synchronous
121+
:tabid: sync
122+
123+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
124+
:start-after: start-cursor-to-list
125+
:end-before: end-cursor-to-list
126+
:language: csharp
127+
:dedent:
128+
129+
.. tab:: Asynchronous
130+
:tabid: async
131+
132+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
133+
:start-after: start-cursor-to-list-async
134+
:end-before: end-cursor-to-list-async
135+
:language: csharp
136+
:dedent:
137+
138+
Tailable Cursors
139+
----------------
140+
141+
When querying on a :manual:`capped collection </core/capped-collections/>`, you
142+
can use a **tailable cursor** that remains open after the client exhausts the
143+
results in a cursor. To create a tailable cursor, create a ``FindOptions`` object and set the
144+
``CursorType`` property to ``CursorType.TailableAwait``. Then, pass the ``FindOptions`` object
145+
to one of the find operation methods. The following example shows how to create a tailable
146+
cursor on a capped collection. Select the :guilabel:`Synchronous` or
147+
:guilabel:`Asynchronous` tab to see the corresponding code:
148+
149+
.. tabs::
150+
151+
.. tab:: Synchronous
152+
:tabid: sync
153+
154+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
155+
:start-after: start-tailable-cursor
156+
:end-before: end-tailable-cursor
157+
:language: csharp
158+
:dedent:
159+
160+
.. tab:: Asynchronous
161+
:tabid: async
162+
163+
.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs
164+
:start-after: start-tailable-cursor-async
165+
:end-before: end-tailable-cursor-async
166+
:language: csharp
167+
:dedent:
168+
169+
API Documentation
170+
-----------------
171+
172+
To learn more about the methods and classes used in this guide, see the
173+
following API documentation:
174+
175+
- `FindSync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.FindSync.html>`__
176+
- `FindAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.FindAsync.html>`__
177+
- `Find() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollectionExtensions.Find.html>`__
178+
- `IAsyncCursor<TDocument> <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IAsyncCursor-1.html>`__
179+
- `FindOptions <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.FindOptions.html>`__
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
using System.Threading.Tasks;
2+
using MongoDB.Bson;
3+
using MongoDB.Bson.Serialization.Attributes;
4+
using MongoDB.Driver;
5+
6+
public class Cursor
7+
{
8+
// Replace with your connection string
9+
private const string MongoConnectionString = "<connection URI>";
10+
11+
public static async Task Main(string[] args)
12+
{
13+
var mongoClient = new MongoClient(MongoConnectionString);
14+
var database = mongoClient.GetDatabase("sample_restaurants");
15+
var collection = database.GetCollection<Restaurant>("restaurants");
16+
17+
{
18+
// start-cursor-iterate
19+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Starbucks");
20+
21+
using (var cursor = collection.FindSync(filter))
22+
{
23+
while (cursor.MoveNext())
24+
{
25+
foreach (var restaurant in cursor.Current)
26+
{
27+
Console.WriteLine(restaurant.Name);
28+
}
29+
}
30+
}
31+
// end-cursor-iterate
32+
}
33+
34+
{
35+
// start-cursor-iterate-async
36+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Starbucks");
37+
38+
using (var cursor = await collection.FindAsync(filter))
39+
{
40+
while (await cursor.MoveNextAsync())
41+
{
42+
foreach (var restaurant in cursor.Current)
43+
{
44+
Console.WriteLine(restaurant.Name);
45+
}
46+
}
47+
}
48+
// end-cursor-iterate-async
49+
}
50+
51+
{
52+
// start-cursor-iterate-to-cursor
53+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Starbucks");
54+
55+
using (var cursor = collection.Find(filter).ToCursor())
56+
{
57+
while (cursor.MoveNext())
58+
{
59+
foreach (var restaurant in cursor.Current)
60+
{
61+
Console.WriteLine(restaurant.Name);
62+
}
63+
}
64+
}
65+
// end-cursor-iterate-to-cursor
66+
}
67+
68+
{
69+
// start-cursor-iterate-to-cursor-async
70+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Starbucks");
71+
72+
using (var cursor = await collection.Find(filter).ToCursorAsync())
73+
{
74+
while (await cursor.MoveNextAsync())
75+
{
76+
foreach (var restaurant in cursor.Current)
77+
{
78+
Console.WriteLine(restaurant.Name);
79+
}
80+
}
81+
}
82+
// end-cursor-iterate-to-cursor-async
83+
}
84+
85+
{
86+
// start-cursor-to-list
87+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Dunkin' Donuts");
88+
var results = collection.FindSync(filter).ToList();
89+
// end-cursor-to-list
90+
}
91+
92+
{
93+
// start-cursor-to-list-async
94+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Dunkin' Donuts");
95+
var results = (await collection.FindAsync(filter)).ToList();
96+
// end-cursor-to-list-async
97+
}
98+
99+
{
100+
// start-tailable-cursor
101+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Dunkin' Donuts");
102+
var options = new FindOptions<Restaurant>
103+
{
104+
CursorType = CursorType.TailableAwait
105+
};
106+
107+
using (var cursor = collection.FindSync(filter, options))
108+
{
109+
while (cursor.MoveNext())
110+
{
111+
foreach (var restaurant in cursor.Current)
112+
{
113+
Console.WriteLine(restaurant.Name);
114+
}
115+
}
116+
}
117+
// end-tailable-cursor
118+
}
119+
120+
{
121+
{
122+
// start-tailable-cursor-async
123+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Name, "Dunkin' Donuts");
124+
var options = new FindOptions<Restaurant>
125+
{
126+
CursorType = CursorType.TailableAwait
127+
};
128+
129+
using (var cursor = await collection.FindAsync(filter, options))
130+
{
131+
while (await cursor.MoveNext())
132+
{
133+
foreach (var restaurant in cursor.Current)
134+
{
135+
Console.WriteLine(restaurant.Name);
136+
}
137+
}
138+
}
139+
// end-tailable-cursor-async
140+
}
141+
}
142+
143+
}
144+
}
145+
146+
// start-restaurant-class
147+
[BsonIgnoreExtraElements]
148+
public class Restaurant
149+
{
150+
public ObjectId Id { get; set; }
151+
152+
[BsonElement("name")]
153+
public string Name { get; set; }
154+
}
155+
// end-restaurant-class

0 commit comments

Comments
 (0)