diff --git a/source/fundamentals/crud/read-operations.txt b/source/fundamentals/crud/read-operations.txt index 60cf8425..82ee4e1e 100644 --- a/source/fundamentals/crud/read-operations.txt +++ b/source/fundamentals/crud/read-operations.txt @@ -12,8 +12,10 @@ Read Operations Retrieve Data Count Documents + /fundamentals/crud/read-operations/distinct Monitor Data Changes - :ref:`csharp-retrieve` - :ref:`csharp-count-documents` +- :ref:`csharp-distinct` - :ref:`csharp-change-streams` diff --git a/source/fundamentals/crud/read-operations/distinct.txt b/source/fundamentals/crud/read-operations/distinct.txt new file mode 100644 index 00000000..743609ae --- /dev/null +++ b/source/fundamentals/crud/read-operations/distinct.txt @@ -0,0 +1,260 @@ +.. _csharp-distinct: + +============================== +Retrieve Distinct Field Values +============================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: read, unique, code example + +Overview +-------- + +In this guide, you can learn how to use the {+driver-short+} to retrieve the +distinct values of a specified field across a collection. + +Within a collection, different documents might contain different values for a +single field. For example, one document in a ``restaurants`` collection has a +``borough`` value of ``"Manhattan"``, and another has a ``borough`` value of +``"Queens"``. By using the {+driver-short+}, you can retrieve all the unique values +that a field contains across multiple documents in a collection. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``sample_restaurants.restaurants`` collection +from the :atlas:`Atlas sample datasets `. To learn how to create a +free MongoDB Atlas cluster and load the sample datasets, see the :ref:``. + +The examples on this page uses the following ``Restaurant`` class to model +the documents in the collection: + +.. literalinclude:: /includes/fundamentals/code-examples/Distinct.cs + :start-after: start-model + :end-before: end-model + :language: csharp + + +Retrieve Distinct Values +------------------------ + +To retrieve the distinct values for a specified field, call the ``Distinct()`` or +``DistinctAsync()`` method of an ``IMongoCollection`` instance and pass the name +of the field you want to find distinct values for. + +Retrieve Values Across a Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example retrieves the distinct values of the ``borough`` field in +the ``restaurants`` collection. Select the :guilabel:`Asynchronous` or :guilabel:`Synchronous` +tab to see the corresponding code. + +.. tabs:: + + .. tab:: Asynchronous + :tabid: distinct-async + + .. io-code-block:: + :copyable: + + .. input:: /includes/fundamentals/code-examples/Distinct.cs + :start-after: start-distinct-async + :end-before: end-distinct-async + :language: csharp + :dedent: + + .. output:: + :visible: false + + Bronx + Brooklyn + Manhattan + Missing + Queens + Staten Island + + .. tab:: Synchronous + :tabid: distinct-sync + + .. io-code-block:: + :copyable: + + .. input:: /includes/fundamentals/code-examples/Distinct.cs + :start-after: start-distinct + :end-before: end-distinct + :language: csharp + :dedent: + + .. output:: + :visible: false + + Bronx + Brooklyn + Manhattan + Missing + Queens + Staten Island + +The operation returns a cursor that you can iterate through to access each distinct ``borough`` +field value. Although several documents have the same value in the ``borough`` field, each value appears +in the results only once. + +Retrieve Values Across Specified Documents +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can provide a **query filter** to the ``Distinct()`` and ``DistinctAsync()`` methods +to find distinct field values within a subset of documents in a collection. A query filter +is an expression that specifies search criteria used to match documents in an operation. +For more information about creating a query filter, see the :ref:`csharp-specify-query` guide. + +The following example retrieves the distinct values of the ``borough`` field for +all documents that have a ``cuisine`` field value of ``"Italian"``. Select the +:guilabel:`Asynchronous` or :guilabel:`Synchronous` tab to see the corresponding code. + +.. tabs:: + + .. tab:: Asynchronous + :tabid: distinct-async + + .. io-code-block:: + :copyable: + + .. input:: /includes/fundamentals/code-examples/Distinct.cs + :start-after: start-distinct-with-query-async + :end-before: end-distinct-with-query-async + :language: csharp + :dedent: + + .. output:: + :visible: false + + Bronx + Brooklyn + Manhattan + Queens + Staten Island + + .. tab:: Synchronous + :tabid: distinct-sync + + .. io-code-block:: + :copyable: + + .. input:: /includes/fundamentals/code-examples/Distinct.cs + :start-after: start-distinct-with-query + :end-before: end-distinct-with-query + :language: csharp + :dedent: + + .. output:: + :visible: false + + Bronx + Brooklyn + Manhattan + Queens + Staten Island + +Modify Distinct Behavior +~~~~~~~~~~~~~~~~~~~~~~~~ + +You can modify the behavior of the ``Distinct()`` and ``DistinctAsync()`` methods by +providing a ``DistinctOptions`` instance as an optional parameter. The following table +describes the properties you can set on a ``DistinctOptions`` instance: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Method + - Description + + * - ``Collation`` + - | Sets the collation to use for the operation. + | **Data type**: `Collation <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.DistinctOptions.Collation.html>`__ + + * - ``MaxTime`` + - | Sets the maximum amount of time that the operation can run. + | **Data type**: ``TimeSpan`` + + * - ``Comment`` + - | Attaches a comment to the operation. + | **Data type**: `BsonValue <{+new-api-root+}/MongoDB.Bson/MongoDB.Bson.BsonValue.html>`__ or ``string`` + +The following example retrieves the distinct values of the ``name`` field for +all documents that have a ``borough`` field value of ``"Bronx"`` and a +``cuisine`` field value of ``"Pizza"``. Then, it adds a comment to the operation by +providing a ``DistinctOptions`` instance to the ``Distinct()`` method. + +Select the :guilabel:`Asynchronous` or :guilabel:`Synchronous` tab to see the +corresponding code. + +.. tabs:: + + .. tab:: Asynchronous + :tabid: distinct-async + + .. io-code-block:: + :copyable: + + .. input:: /includes/fundamentals/code-examples/Distinct.cs + :start-after: start-distinct-with-comment-async + :end-before: end-distinct-with-comment-async + :language: csharp + :dedent: + + .. output:: + :visible: false + + $1.25 Pizza + 18 East Gunhill Pizza + 2 Bros + Aenos Pizza + Alitalia Pizza Restaurant + Amici Pizza And Pasta + Angie'S Cafe Pizza + ... + + .. tab:: Synchronous + :tabid: distinct-sync + + .. io-code-block:: + :copyable: + + .. input:: /includes/fundamentals/code-examples/Distinct.cs + :start-after: start-distinct-with-comment + :end-before: end-distinct-with-comment + :language: csharp + :dedent: + + .. output:: + :visible: false + + $1.25 Pizza + 18 East Gunhill Pizza + 2 Bros + Aenos Pizza + Alitalia Pizza Restaurant + Amici Pizza And Pasta + Angie'S Cafe Pizza + ... + +API Documentation +----------------- + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `Distinct() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.Distinct.html>`__ +- `DistinctAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.DistinctAsync.html>`__ +- `DistinctOptions <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.DistinctOptions.html>`__ \ No newline at end of file diff --git a/source/includes/fundamentals/code-examples/Distinct.cs b/source/includes/fundamentals/code-examples/Distinct.cs new file mode 100644 index 00000000..79d0e619 --- /dev/null +++ b/source/includes/fundamentals/code-examples/Distinct.cs @@ -0,0 +1,105 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Driver; + +public class Distinct +{ + // Replace with your connection string + private const string MongoConnectionString = ">"; + + public static void Main(string[] args) + { + var mongoClient = new MongoClient(MongoConnectionString); + var database = mongoClient.GetDatabase("sample_restaurants"); + var collection = database.GetCollection("restaurants"); + + { + // start-distinct + var results = collection.Distinct(r => r.Borough, Builders.Filters.Empty).ToList(); + foreach (var result in results) + { + Console.WriteLine(result); + } + // end-distinct + } + + { + // start-distinct-with-query + var filter = Builders.Filter.Eq(r => r.Cuisine, "Italian"); + var results = collection.Distinct(r => r.Borough, filter).ToList(); + foreach (var result in results) + { + Console.WriteLine(result); + } + // end-distinct-with-query + } + + { + // start-distinct-with-comment + var cuisineFilter = Builders.Filter.Eq(r => r.Cuisine, "Pizza"); + var boroughFilter = Builders.Filter.Eq(r => r.Borough, "Bronx"); + var filter = Builders.Filter.And(cuisineFilter, boroughFilter); + + var options = new DistinctOptions { + Comment = "Find all Italian restaurants in the Bronx" + }; + + var results = collection.Distinct(r => r.Name, filter).ToList(); + foreach (var result in results) + { + Console.WriteLine(result); + } + // end-distinct-with-comment + } + + } + + private static async void DistinctAsync (IMongoCollection collection) + { + // start-distinct-async + var results = await collection.DistinctAsync(r => r.Borough, Builders.Filters.Empty); + await results.ForEachAsync(result => Console.WriteLine(result)); + // end-distinct-async + } + + private static async void DistinctWithQueryAsync (IMongoCollection collection) + { + // start-distinct-with-query-async + var filter = Builders.Filter.Eq(r => r.Cuisine, "Italian"); + var results = await collection.DistinctAsync(r => r.Borough, filter); + await results.ForEachAsync(result => Console.WriteLine(result)); + // end-distinct-with-query-async + } + + private static async void DistinctWithCommentAsync (IMongoCollection collection) + { + // start-distinct-with-comment-async + var cuisineFilter = Builders.Filter.Eq(r => r.Cuisine, "Pizza"); + var boroughFilter = Builders.Filter.Eq(r => r.Borough, "Bronx"); + var filter = Builders.Filter.And(cuisineFilter, boroughFilter); + + var options = new DistinctOptions { + Comment = "Find all Italian restaurants in the Bronx" + }; + + var results = await collection.DistinctAsync(r => r.Name, filter, options); + await results.ForEachAsync(result => Console.WriteLine(result)); + // end-distinct-with-comment-async + } +} + +// start-model +public class Restaurant { + public ObjectId? Id { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("cuisine")] + public string? Cuisine { get; set; } + + [BsonElement("borough")] + public string? Borough { get; set; } +} +// end-model \ No newline at end of file