-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathcursor.sort.txt
408 lines (274 loc) · 13 KB
/
cursor.sort.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
=============
cursor.sort()
=============
.. default-domain:: mongodb
.. facet::
:name: programming_language
:values: shell
.. meta::
:description: The MongoDB cursor sort method specifies the order of matching documents that a query returns.
.. contents:: On this page
:local:
:backlinks: none
:depth: 1
:class: singlecol
Definition
----------
.. method:: cursor.sort(sort)
.. include:: /includes/fact-mongosh-shell-method.rst
Specifies the order in which the query returns matching documents.
You must apply :method:`~cursor.sort()` to the cursor before
retrieving any documents from the database.
Compatibility
-------------
This method is available in deployments hosted in the following environments:
.. include:: /includes/fact-environments-atlas-only.rst
.. include:: /includes/fact-environments-atlas-support-all.rst
.. include:: /includes/fact-environments-onprem-only.rst
Syntax
------
The :method:`~cursor.sort()` method has the following parameter:
.. list-table::
:header-rows: 1
:widths: 20 20 80
* - Parameter
- Type
- Description
* - ``sort``
- document
- A document that defines the sort order of the result set.
The ``sort`` parameter contains field and value pairs, in the
following form:
.. code-block:: javascript
{ field: value }
The sort document can specify :ref:`ascending or descending sort on
existing fields <sort-asc-desc>` or :ref:`sort on text score metadata
<sort-metadata>`.
Behavior
--------
Limits
~~~~~~
.. include:: /includes/sort-limits.rst
.. _sort-cursor-consistent-sorting:
Sort Consistency
~~~~~~~~~~~~~~~~
.. include:: /includes/fact-sort-consistency.rst
Consider the following ``restaurant`` collection:
.. code-block:: js
db.restaurants.insertMany( [
{ "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan"},
{ "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens"},
{ "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn"},
{ "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan"},
{ "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn"},
] );
The following command uses the :method:`~cursor.sort()` method to sort
on the ``borough`` field:
.. code-block:: js
db.restaurants.find().sort( { "borough": 1 } )
In this example, sort order may be inconsistent, since the ``borough``
field contains duplicate values for both ``Manhattan`` and ``Brooklyn``.
Documents are returned in alphabetical order by ``borough``, but the
order of those documents with duplicate values for ``borough`` might not
be the same across multiple executions of the same sort. For example,
here are the results from two different executions of the above command:
.. code-block:: js
:copyable: false
{ "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" }
{ "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" }
{ "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" }
{ "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" }
{ "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" }
{ "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" }
{ "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" }
{ "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" }
{ "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" }
{ "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" }
While the values for ``borough`` are still sorted in alphabetical order,
the order of the documents containing duplicate values for ``borough``
(i.e. ``Manhattan`` and ``Brooklyn``) is not the same.
To achieve a *consistent sort*, add a field which contains exclusively
unique values to the sort. The following command uses the
:method:`~cursor.sort()` method to sort on both the ``borough`` field
and the ``_id`` field:
.. code-block:: js
db.restaurants.find().sort( { "borough": 1, "_id": 1 } )
Since the ``_id`` field is always guaranteed to contain exclusively
unique values, the returned sort order will always be the same across
multiple executions of the same sort.
.. _sort-asc-desc:
Ascending/Descending Sort
~~~~~~~~~~~~~~~~~~~~~~~~~
Specify in the sort parameter the field or fields to sort by and a
value of ``1`` or ``-1`` to specify an ascending or descending sort
respectively.
The following operation sorts the documents first by the ``age`` field
in descending order and then by the ``posts`` field in ascending order:
.. code-block:: javascript
db.users.find({ }).sort( { age : -1, posts: 1 } )
.. include:: /includes/fact-sort-order.rst
For details on the comparison/sort order for specific types, see
:ref:`bson-types-comparison-order`.
.. _sort-metadata:
Text Score Metadata Sort
~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: /includes/text-search-legacy-atlas-section.rst
If you use :query:`$text`, you can sort by descending relevance score
using the :expression:`{ $meta: "textScore" } <$meta>` expression.
The following sample document specifies a descending sort by the
``"textScore"`` metadata:
.. code-block:: javascript
db.users.find(
{ $text: { $search: "operating" } },
{ score: { $meta: "textScore" }}
).sort({ score: { $meta: "textScore" } })
The ``"textScore"`` metadata sorts in descending order.
For more information, see :expression:`$meta` for details.
.. _sort-by-array:
Sort by an Array Field
~~~~~~~~~~~~~~~~~~~~~~
.. include:: /includes/array-sort-example-setup.rst
The following queries sort the documents by the ``sizes`` field in
ascending and descending order:
.. code-block:: javascript
// Ascending sort
db.shoes.find().sort( { sizes: 1 } )
// Descending sort
db.shoes.find().sort( { sizes: -1 } )
.. include:: /includes/array-sort-example-explanation.rst
Filter and Sort by an Array Field
`````````````````````````````````
.. include:: /includes/array-filter-and-sort-example-setup.rst
.. code-block:: javascript
db.shoes.find( { sizes: { $gt: 9 } } ).sort( { sizes: 1 } )
.. include:: /includes/array-filter-and-sort-example-explanation.rst
.. tip:: Sort only by Matched Values
To only consider matched values as potential sort keys, you can
generate a new field containing the matched values and sort on that
field. For more information, see these pipeline stages and
expressions:
- :pipeline:`$addFields`
- :expression:`$filter`
- :pipeline:`$sort`
.. _sort-index-use:
Sort and Index Use
~~~~~~~~~~~~~~~~~~
MongoDB can obtain the results of a sort operation from an index which
includes the sort fields. MongoDB *may* use multiple indexes to support
a sort operation *if* the sort uses the same indexes as the query
predicate.
If MongoDB cannot use an index or indexes to obtain the sort
order, MongoDB must perform a blocking sort operation on the data.
A blocking sort indicates that MongoDB must consume and process all
input documents to the sort before returning results. Blocking sorts do
not block concurrent operations on the collection or database.
Sort operations that use an index often have better performance than
blocking sorts. For more information on creating indexes to support
sort operations, see :ref:`sorting-with-indexes`.
If MongoDB requires using more than 100 megabytes of system memory for
the blocking sort operation, MongoDB returns an error *unless* the query
specifies :method:`cursor.allowDiskUse()`.
:method:`~cursor.allowDiskUse()` allows MongoDB to use temporary files
on disk to store data exceeding the 100 megabyte system memory limit
while processing a blocking sort operation.
To check if MongoDB must perform a blocking sort, append
:method:`cursor.explain()` to the query and check the
:ref:`explain results <explain-results>`. If the query plan
contains a ``SORT`` stage, then MongoDB must perform a
blocking sort operation subject to the 100 megabyte memory limit.
To prevent blocking sorts from consuming too much memory:
- Create an index to support the sort operation. See
:doc:`/tutorial/sort-results-with-indexes` for more information and
examples.
- Limit the amount of data to sort by using :method:`cursor.limit()`
with :method:`cursor.sort()`. See :ref:`sort-limit-results` for more
information and examples.
.. seealso::
:limit:`Memory Limits on Sort Operations <Sort Operations>`
.. _sort-limit-results:
Limit Results
~~~~~~~~~~~~~
You can use :method:`~cursor.sort()` in conjunction with
:method:`~cursor.limit()` to return the first (in terms of the sort
order) ``k`` documents, where ``k`` is the specified limit.
If MongoDB cannot obtain the sort order via an index scan, then MongoDB
uses a top-k sort algorithm. This algorithm buffers the first ``k``
results (or last, depending on the sort order) seen so far by the
underlying index or collection access. If at any point the memory
footprint of these ``k`` results exceeds 100 megabytes, the query will
fail *unless* the query specifies :method:`cursor.allowDiskUse()`.
.. seealso::
:limit:`Memory Limits on Sort Operations <Sort Operations>`
.. _sort-with-projection:
Interaction with Projection
~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a set of results are both sorted *and*
:term:`projected <projection>`, the MongoDB query engine will always
apply the sorting **first**.
Examples
--------
A collection ``orders`` contain the following documents:
.. code-block:: javascript
{ _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 }
{ _id: 2, item: { category: "cookies", type: "chocolate chip" }, amount: 50 }
{ _id: 3, item: { category: "cookies", type: "chocolate chip" }, amount: 15 }
{ _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 }
{ _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 }
{ _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 }
The following query, which returns all documents from the ``orders``
collection, does not specify a sort order:
.. code-block:: javascript
db.orders.find()
The query returns the documents in indeterminate order:
.. code-block:: none
{ "_id" : 1, "item" : { "category" : "cake", "type" : "chiffon" }, "amount" : 10 }
{ "_id" : 2, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 50 }
{ "_id" : 3, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 15 }
{ "_id" : 4, "item" : { "category" : "cake", "type" : "lemon" }, "amount" : 30 }
{ "_id" : 5, "item" : { "category" : "cake", "type" : "carrot" }, "amount" : 20 }
{ "_id" : 6, "item" : { "category" : "brownies", "type" : "blondie" }, "amount" : 10 }
The following query specifies a sort on the ``amount`` field in
descending order.
.. code-block:: javascript
db.orders.find().sort( { amount: -1 } )
The query returns the following documents, in descending order of
``amount``:
.. code-block:: javascript
{ "_id" : 2, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 50 }
{ "_id" : 4, "item" : { "category" : "cake", "type" : "lemon" }, "amount" : 30 }
{ "_id" : 5, "item" : { "category" : "cake", "type" : "carrot" }, "amount" : 20 }
{ "_id" : 3, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 15 }
{ "_id" : 1, "item" : { "category" : "cake", "type" : "chiffon" }, "amount" : 10 }
{ "_id" : 6, "item" : { "category" : "brownies", "type" : "blondie" }, "amount" : 10 }
The following query specifies the sort order using the fields from an
embedded document ``item``. The query sorts first by the ``category`` field
in ascending order, and then within each ``category``, by the ``type``
field in ascending order.
.. code-block:: javascript
db.orders.find().sort( { "item.category": 1, "item.type": 1 } )
The query returns the following documents, ordered first by the
``category`` field, and within each category, by the ``type`` field:
.. code-block:: javascript
{ "_id" : 6, "item" : { "category" : "brownies", "type" : "blondie" }, "amount" : 10 }
{ "_id" : 5, "item" : { "category" : "cake", "type" : "carrot" }, "amount" : 20 }
{ "_id" : 1, "item" : { "category" : "cake", "type" : "chiffon" }, "amount" : 10 }
{ "_id" : 4, "item" : { "category" : "cake", "type" : "lemon" }, "amount" : 30 }
{ "_id" : 2, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 50 }
{ "_id" : 3, "item" : { "category" : "cookies", "type" : "chocolate chip" }, "amount" : 15 }
.. _return-storage-order:
.. _return-natural-order:
Return in Natural Order
-----------------------
The :operator:`$natural` parameter returns items according to their
:term:`natural order` within the database. This ordering is an internal
implementation feature, and you should not rely on any particular
ordering of the documents.
Index Use
~~~~~~~~~
Queries that include a sort by :operator:`$natural` order do **not**
use indexes to fulfill the query predicate with the following
exception: If the query predicate is an equality condition on the
``_id`` field ``{ _id: <value> }``, then the query with the sort by
:operator:`$natural` order can use the ``_id`` index.
.. seealso::
:operator:`$natural`