diff --git a/source/crud/query/cursors.txt b/source/crud/query/cursors.txt index e69de29b..a3307199 100644 --- a/source/crud/query/cursors.txt +++ b/source/crud/query/cursors.txt @@ -0,0 +1,179 @@ +.. _csharp-cursors: + +========================= +Access Data From a Cursor +========================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: read, results, oplog + +Overview +-------- + +In this guide, you can learn how to access data from a **cursor** by using the +{+driver-short+}. + +A cursor is a tool that returns the results of a read operation in iterable +batches. Because a cursor holds only a subset of documents at any given time, +cursors reduce both memory consumption and network bandwidth usage. + +You can retrieve a cursor by using the ``FindSync()`` or ``FindAsync()`` method. You can +also convert the results of the ``Find()`` method to a cursor by chaining the ``ToCursor()`` +or ``ToCursorAsync()`` method. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection +in the ``sample_restaurants`` database provided in the :atlas:`Atlas sample datasets `. +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, +see the :ref:`` tutorial. + +The examples on this page use the following ``Restaurant`` object to model the documents +in the ``restaurants`` collection: + +.. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-restaurant-class + :end-before: end-restaurant-class + :language: csharp + +.. _csharp-cursors-iterate: + +Access Cursor Contents Iteratively +---------------------------------- + +To iterate over the contents of a cursor, use a ``foreach`` loop inside a ``using`` block. +The following example retrieves documents from the ``restaurants`` collection in which the +value of the ``name`` field is ``"Starbucks"``, then iterates over the results. +Select the :guilabel:`Synchronous` or :guilabel:`Asynchronous` tab to see the corresponding +code: + +.. tabs:: + + .. tab:: Synchronous + :tabid: sync + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-cursor-iterate + :end-before: end-cursor-iterate + :language: csharp + :dedent: + + .. tab:: Asynchronous + :tabid: async + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-cursor-iterate-async + :end-before: end-cursor-iterate-async + :language: csharp + :dedent: + +The following example performs the same operation but uses the ``ToCursor()`` method. +Select the :guilabel:`Synchronous` or :guilabel:`Asynchronous` +tab to see the corresponding code: + +.. tabs:: + + .. tab:: Synchronous + :tabid: sync + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-cursor-iterate-to-cursor + :end-before: end-cursor-iterate-to-cursor + :language: csharp + :dedent: + + .. tab:: Asynchronous + :tabid: async + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-cursor-iterate-to-cursor-async + :end-before: end-cursor-iterate-to-cursor-async + :language: csharp + :dedent: + +Retrieve All Documents +---------------------- + +.. warning:: + + If the number and size of documents returned by your query exceeds available + application memory, your program might crash. If you expect a large result + set, :ref:`access your cursor iteratively `. + +To retrieve all documents from a cursor, use the ``ToList()`` method, as shown in the +following example. Select the :guilabel:`Synchronous` or :guilabel:`Asynchronous` +tab to see the corresponding code: + +.. tabs:: + + .. tab:: Synchronous + :tabid: sync + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-cursor-to-list + :end-before: end-cursor-to-list + :language: csharp + :dedent: + + .. tab:: Asynchronous + :tabid: async + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-cursor-to-list-async + :end-before: end-cursor-to-list-async + :language: csharp + :dedent: + +Tailable Cursors +---------------- + +When querying on a :manual:`capped collection `, you +can use a **tailable cursor** that remains open after the client exhausts the +results in a cursor. To create a tailable cursor, create a ``FindOptions`` object and set the +``CursorType`` property to ``CursorType.TailableAwait``. Then, pass the ``FindOptions`` object +to one of the find operation methods. The following example shows how to create a tailable +cursor on a capped collection. Select the :guilabel:`Synchronous` or +:guilabel:`Asynchronous` tab to see the corresponding code: + +.. tabs:: + + .. tab:: Synchronous + :tabid: sync + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-tailable-cursor + :end-before: end-tailable-cursor + :language: csharp + :dedent: + + .. tab:: Asynchronous + :tabid: async + + .. literalinclude:: /includes/fundamentals/code-examples/Cursor.cs + :start-after: start-tailable-cursor-async + :end-before: end-tailable-cursor-async + :language: csharp + :dedent: + +API Documentation +----------------- + +To learn more about the methods and classes used in this guide, see the +following API documentation: + +- `FindSync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.FindSync.html>`__ +- `FindAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.FindAsync.html>`__ +- `Find() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollectionExtensions.Find.html>`__ +- `IAsyncCursor <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IAsyncCursor-1.html>`__ +- `FindOptions <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.FindOptions.html>`__ diff --git a/source/includes/fundamentals/code-examples/Cursor.cs b/source/includes/fundamentals/code-examples/Cursor.cs new file mode 100644 index 00000000..c8de98a2 --- /dev/null +++ b/source/includes/fundamentals/code-examples/Cursor.cs @@ -0,0 +1,155 @@ +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; + +public class Cursor +{ + // Replace with your connection string + private const string MongoConnectionString = ""; + + public static async Task Main(string[] args) + { + var mongoClient = new MongoClient(MongoConnectionString); + var database = mongoClient.GetDatabase("sample_restaurants"); + var collection = database.GetCollection("restaurants"); + + { + // start-cursor-iterate + var filter = Builders.Filter.Eq(r => r.Name, "Starbucks"); + + using (var cursor = collection.FindSync(filter)) + { + while (cursor.MoveNext()) + { + foreach (var restaurant in cursor.Current) + { + Console.WriteLine(restaurant.Name); + } + } + } + // end-cursor-iterate + } + + { + // start-cursor-iterate-async + var filter = Builders.Filter.Eq(r => r.Name, "Starbucks"); + + using (var cursor = await collection.FindAsync(filter)) + { + while (await cursor.MoveNextAsync()) + { + foreach (var restaurant in cursor.Current) + { + Console.WriteLine(restaurant.Name); + } + } + } + // end-cursor-iterate-async + } + + { + // start-cursor-iterate-to-cursor + var filter = Builders.Filter.Eq(r => r.Name, "Starbucks"); + + using (var cursor = collection.Find(filter).ToCursor()) + { + while (cursor.MoveNext()) + { + foreach (var restaurant in cursor.Current) + { + Console.WriteLine(restaurant.Name); + } + } + } + // end-cursor-iterate-to-cursor + } + + { + // start-cursor-iterate-to-cursor-async + var filter = Builders.Filter.Eq(r => r.Name, "Starbucks"); + + using (var cursor = await collection.Find(filter).ToCursorAsync()) + { + while (await cursor.MoveNextAsync()) + { + foreach (var restaurant in cursor.Current) + { + Console.WriteLine(restaurant.Name); + } + } + } + // end-cursor-iterate-to-cursor-async + } + + { + // start-cursor-to-list + var filter = Builders.Filter.Eq(r => r.Name, "Dunkin' Donuts"); + var results = collection.FindSync(filter).ToList(); + // end-cursor-to-list + } + + { + // start-cursor-to-list-async + var filter = Builders.Filter.Eq(r => r.Name, "Dunkin' Donuts"); + var results = (await collection.FindAsync(filter)).ToList(); + // end-cursor-to-list-async + } + + { + // start-tailable-cursor + var filter = Builders.Filter.Eq(r => r.Name, "Dunkin' Donuts"); + var options = new FindOptions + { + CursorType = CursorType.TailableAwait + }; + + using (var cursor = collection.FindSync(filter, options)) + { + while (cursor.MoveNext()) + { + foreach (var restaurant in cursor.Current) + { + Console.WriteLine(restaurant.Name); + } + } + } + // end-tailable-cursor + } + + { + { + // start-tailable-cursor-async + var filter = Builders.Filter.Eq(r => r.Name, "Dunkin' Donuts"); + var options = new FindOptions + { + CursorType = CursorType.TailableAwait + }; + + using (var cursor = await collection.FindAsync(filter, options)) + { + while (await cursor.MoveNext()) + { + foreach (var restaurant in cursor.Current) + { + Console.WriteLine(restaurant.Name); + } + } + } + // end-tailable-cursor-async + } + } + + } +} + +// start-restaurant-class +[BsonIgnoreExtraElements] +public class Restaurant +{ + public ObjectId Id { get; set; } + + [BsonElement("name")] + public string Name { get; set; } +} +// end-restaurant-class \ No newline at end of file