Skip to content

Commit 16f6f4b

Browse files
committed
DOCSP-45007: Distinct (#292)
(cherry picked from commit 341fcf8)
1 parent e45154a commit 16f6f4b

File tree

3 files changed

+370
-3
lines changed

3 files changed

+370
-3
lines changed

source/fundamentals/crud/read-operations.txt

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ Read Operations
1010
.. toctree::
1111
:caption: Read Operations
1212

13-
/fundamentals/crud/read-operations/retrieve
14-
/fundamentals/crud/read-operations/count
15-
/fundamentals/crud/read-operations/change-streams
13+
Retrieve Data </fundamentals/crud/read-operations/retrieve>
14+
Count Documents </fundamentals/crud/read-operations/count>
15+
/fundamentals/crud/read-operations/distinct
16+
Monitor Data Changes </fundamentals/crud/read-operations/change-streams>
1617

1718
- :ref:`csharp-retrieve`
1819
- :ref:`csharp-count-documents`
20+
- :ref:`csharp-distinct`
1921
- :ref:`csharp-change-streams`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
.. _csharp-distinct:
2+
3+
==============================
4+
Retrieve Distinct Field Values
5+
==============================
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 2
11+
:class: singlecol
12+
13+
.. facet::
14+
:name: genre
15+
:values: reference
16+
17+
.. meta::
18+
:keywords: read, unique, code example
19+
20+
Overview
21+
--------
22+
23+
In this guide, you can learn how to use the {+driver-short+} to retrieve the
24+
distinct values of a specified field across a collection.
25+
26+
Within a collection, different documents might contain different values for a
27+
single field. For example, one document in a ``restaurants`` collection has a
28+
``borough`` value of ``"Manhattan"``, and another has a ``borough`` value of
29+
``"Queens"``. By using the {+driver-short+}, you can retrieve all the unique values
30+
that a field contains across multiple documents in a collection.
31+
32+
Sample Data
33+
~~~~~~~~~~~
34+
35+
The examples in this guide use the ``sample_restaurants.restaurants`` collection
36+
from the :atlas:`Atlas sample datasets </sample-data>`. To learn how to create a
37+
free MongoDB Atlas cluster and load the sample datasets, see the :ref:`<csharp-quickstart>`.
38+
39+
The examples on this page uses the following ``Restaurant`` class to model
40+
the documents in the collection:
41+
42+
.. literalinclude:: /includes/fundamentals/code-examples/Distinct.cs
43+
:start-after: start-model
44+
:end-before: end-model
45+
:language: csharp
46+
47+
48+
Retrieve Distinct Values
49+
------------------------
50+
51+
To retrieve the distinct values for a specified field, call the ``Distinct()`` or
52+
``DistinctAsync()`` method of an ``IMongoCollection<TDocument>`` instance and pass the name
53+
of the field you want to find distinct values for.
54+
55+
Retrieve Values Across a Collection
56+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
57+
58+
The following example retrieves the distinct values of the ``borough`` field in
59+
the ``restaurants`` collection. Select the :guilabel:`Asynchronous` or :guilabel:`Synchronous`
60+
tab to see the corresponding code.
61+
62+
.. tabs::
63+
64+
.. tab:: Asynchronous
65+
:tabid: distinct-async
66+
67+
.. io-code-block::
68+
:copyable:
69+
70+
.. input:: /includes/fundamentals/code-examples/Distinct.cs
71+
:start-after: start-distinct-async
72+
:end-before: end-distinct-async
73+
:language: csharp
74+
:dedent:
75+
76+
.. output::
77+
:visible: false
78+
79+
Bronx
80+
Brooklyn
81+
Manhattan
82+
Missing
83+
Queens
84+
Staten Island
85+
86+
.. tab:: Synchronous
87+
:tabid: distinct-sync
88+
89+
.. io-code-block::
90+
:copyable:
91+
92+
.. input:: /includes/fundamentals/code-examples/Distinct.cs
93+
:start-after: start-distinct
94+
:end-before: end-distinct
95+
:language: csharp
96+
:dedent:
97+
98+
.. output::
99+
:visible: false
100+
101+
Bronx
102+
Brooklyn
103+
Manhattan
104+
Missing
105+
Queens
106+
Staten Island
107+
108+
The operation returns a cursor that you can iterate through to access each distinct ``borough``
109+
field value. Although several documents have the same value in the ``borough`` field, each value appears
110+
in the results only once.
111+
112+
Retrieve Values Across Specified Documents
113+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
114+
115+
You can provide a **query filter** to the ``Distinct()`` and ``DistinctAsync()`` methods
116+
to find distinct field values within a subset of documents in a collection. A query filter
117+
is an expression that specifies search criteria used to match documents in an operation.
118+
For more information about creating a query filter, see the :ref:`csharp-specify-query` guide.
119+
120+
The following example retrieves the distinct values of the ``borough`` field for
121+
all documents that have a ``cuisine`` field value of ``"Italian"``. Select the
122+
:guilabel:`Asynchronous` or :guilabel:`Synchronous` tab to see the corresponding code.
123+
124+
.. tabs::
125+
126+
.. tab:: Asynchronous
127+
:tabid: distinct-async
128+
129+
.. io-code-block::
130+
:copyable:
131+
132+
.. input:: /includes/fundamentals/code-examples/Distinct.cs
133+
:start-after: start-distinct-with-query-async
134+
:end-before: end-distinct-with-query-async
135+
:language: csharp
136+
:dedent:
137+
138+
.. output::
139+
:visible: false
140+
141+
Bronx
142+
Brooklyn
143+
Manhattan
144+
Queens
145+
Staten Island
146+
147+
.. tab:: Synchronous
148+
:tabid: distinct-sync
149+
150+
.. io-code-block::
151+
:copyable:
152+
153+
.. input:: /includes/fundamentals/code-examples/Distinct.cs
154+
:start-after: start-distinct-with-query
155+
:end-before: end-distinct-with-query
156+
:language: csharp
157+
:dedent:
158+
159+
.. output::
160+
:visible: false
161+
162+
Bronx
163+
Brooklyn
164+
Manhattan
165+
Queens
166+
Staten Island
167+
168+
Modify Distinct Behavior
169+
~~~~~~~~~~~~~~~~~~~~~~~~
170+
171+
You can modify the behavior of the ``Distinct()`` and ``DistinctAsync()`` methods by
172+
providing a ``DistinctOptions`` instance as an optional parameter. The following table
173+
describes the properties you can set on a ``DistinctOptions`` instance:
174+
175+
.. list-table::
176+
:widths: 30 70
177+
:header-rows: 1
178+
179+
* - Method
180+
- Description
181+
182+
* - ``Collation``
183+
- | Sets the collation to use for the operation.
184+
| **Data type**: `Collation <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.DistinctOptions.Collation.html>`__
185+
186+
* - ``MaxTime``
187+
- | Sets the maximum amount of time that the operation can run.
188+
| **Data type**: ``TimeSpan``
189+
190+
* - ``Comment``
191+
- | Attaches a comment to the operation.
192+
| **Data type**: `BsonValue <{+new-api-root+}/MongoDB.Bson/MongoDB.Bson.BsonValue.html>`__ or ``string``
193+
194+
The following example retrieves the distinct values of the ``name`` field for
195+
all documents that have a ``borough`` field value of ``"Bronx"`` and a
196+
``cuisine`` field value of ``"Pizza"``. Then, it adds a comment to the operation by
197+
providing a ``DistinctOptions`` instance to the ``Distinct()`` method.
198+
199+
Select the :guilabel:`Asynchronous` or :guilabel:`Synchronous` tab to see the
200+
corresponding code.
201+
202+
.. tabs::
203+
204+
.. tab:: Asynchronous
205+
:tabid: distinct-async
206+
207+
.. io-code-block::
208+
:copyable:
209+
210+
.. input:: /includes/fundamentals/code-examples/Distinct.cs
211+
:start-after: start-distinct-with-comment-async
212+
:end-before: end-distinct-with-comment-async
213+
:language: csharp
214+
:dedent:
215+
216+
.. output::
217+
:visible: false
218+
219+
$1.25 Pizza
220+
18 East Gunhill Pizza
221+
2 Bros
222+
Aenos Pizza
223+
Alitalia Pizza Restaurant
224+
Amici Pizza And Pasta
225+
Angie'S Cafe Pizza
226+
...
227+
228+
.. tab:: Synchronous
229+
:tabid: distinct-sync
230+
231+
.. io-code-block::
232+
:copyable:
233+
234+
.. input:: /includes/fundamentals/code-examples/Distinct.cs
235+
:start-after: start-distinct-with-comment
236+
:end-before: end-distinct-with-comment
237+
:language: csharp
238+
:dedent:
239+
240+
.. output::
241+
:visible: false
242+
243+
$1.25 Pizza
244+
18 East Gunhill Pizza
245+
2 Bros
246+
Aenos Pizza
247+
Alitalia Pizza Restaurant
248+
Amici Pizza And Pasta
249+
Angie'S Cafe Pizza
250+
...
251+
252+
API Documentation
253+
-----------------
254+
255+
To learn more about any of the methods or types discussed in this
256+
guide, see the following API documentation:
257+
258+
- `Distinct() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.Distinct.html>`__
259+
- `DistinctAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IMongoCollection-1.DistinctAsync.html>`__
260+
- `DistinctOptions <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.DistinctOptions.html>`__
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using MongoDB.Bson;
2+
using MongoDB.Bson.Serialization.Attributes;
3+
using MongoDB.Bson.Serialization.Conventions;
4+
using MongoDB.Driver;
5+
6+
public class Distinct
7+
{
8+
// Replace with your connection string
9+
private const string MongoConnectionString = "<connection string URI>>";
10+
11+
public static void 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-distinct
19+
var results = collection.Distinct<string>(r => r.Borough, Builders<Restaurant>.Filters.Empty).ToList();
20+
foreach (var result in results)
21+
{
22+
Console.WriteLine(result);
23+
}
24+
// end-distinct
25+
}
26+
27+
{
28+
// start-distinct-with-query
29+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Cuisine, "Italian");
30+
var results = collection.Distinct<string>(r => r.Borough, filter).ToList();
31+
foreach (var result in results)
32+
{
33+
Console.WriteLine(result);
34+
}
35+
// end-distinct-with-query
36+
}
37+
38+
{
39+
// start-distinct-with-comment
40+
var cuisineFilter = Builders<Restaurant>.Filter.Eq(r => r.Cuisine, "Pizza");
41+
var boroughFilter = Builders<Restaurant>.Filter.Eq(r => r.Borough, "Bronx");
42+
var filter = Builders<Restaurant>.Filter.And(cuisineFilter, boroughFilter);
43+
44+
var options = new DistinctOptions {
45+
Comment = "Find all Italian restaurants in the Bronx"
46+
};
47+
48+
var results = collection.Distinct<string>(r => r.Name, filter).ToList();
49+
foreach (var result in results)
50+
{
51+
Console.WriteLine(result);
52+
}
53+
// end-distinct-with-comment
54+
}
55+
56+
}
57+
58+
private static async void DistinctAsync (IMongoCollection<Restaurant> collection)
59+
{
60+
// start-distinct-async
61+
var results = await collection.DistinctAsync<string>(r => r.Borough, Builders<Restaurant>.Filters.Empty);
62+
await results.ForEachAsync(result => Console.WriteLine(result));
63+
// end-distinct-async
64+
}
65+
66+
private static async void DistinctWithQueryAsync (IMongoCollection<Restaurant> collection)
67+
{
68+
// start-distinct-with-query-async
69+
var filter = Builders<Restaurant>.Filter.Eq(r => r.Cuisine, "Italian");
70+
var results = await collection.DistinctAsync<string>(r => r.Borough, filter);
71+
await results.ForEachAsync(result => Console.WriteLine(result));
72+
// end-distinct-with-query-async
73+
}
74+
75+
private static async void DistinctWithCommentAsync (IMongoCollection<Restaurant> collection)
76+
{
77+
// start-distinct-with-comment-async
78+
var cuisineFilter = Builders<Restaurant>.Filter.Eq(r => r.Cuisine, "Pizza");
79+
var boroughFilter = Builders<Restaurant>.Filter.Eq(r => r.Borough, "Bronx");
80+
var filter = Builders<Restaurant>.Filter.And(cuisineFilter, boroughFilter);
81+
82+
var options = new DistinctOptions {
83+
Comment = "Find all Italian restaurants in the Bronx"
84+
};
85+
86+
var results = await collection.DistinctAsync<string>(r => r.Name, filter, options);
87+
await results.ForEachAsync(result => Console.WriteLine(result));
88+
// end-distinct-with-comment-async
89+
}
90+
}
91+
92+
// start-model
93+
public class Restaurant {
94+
public ObjectId? Id { get; set; }
95+
96+
[BsonElement("name")]
97+
public string? Name { get; set; }
98+
99+
[BsonElement("cuisine")]
100+
public string? Cuisine { get; set; }
101+
102+
[BsonElement("borough")]
103+
public string? Borough { get; set; }
104+
}
105+
// end-model

0 commit comments

Comments
 (0)