@@ -169,72 +169,32 @@ The optimizer can add the same :pipeline:`$match` stage before the
169169 { $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
170170 { $match: { year: 2014, category: { $ne: "Z" } } }
171171
172- .. _agg-skip-limit -optimization:
172+ .. _agg-project-skip -optimization:
173173
174- ``$skip`` + ``$limit`` Sequence Optimization
175- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176-
177- When you have a sequence with :pipeline:`$skip` followed by a
178- :pipeline:`$limit`, the :pipeline:`$limit` moves before the
179- :pipeline:`$skip`. With the reordering, the :pipeline:`$limit` value
180- increases by the :pipeline:`$skip` amount.
181-
182- For example, if the pipeline consists of the following stages:
183-
184- .. code-block:: javascript
185-
186- { $skip: 10 },
187- { $limit: 5 }
188-
189- During the optimization phase, the optimizer transforms the sequence to
190- the following:
191-
192- .. code-block:: javascript
193-
194- { $limit: 15 },
195- { $skip: 10 }
196-
197- This optimization allows for more opportunities for
198- :ref:`agg-sort-limit-coalescence`, such as with ``$sort`` + ``$skip`` +
199- ``$limit`` sequences. See :ref:`agg-sort-limit-coalescence` for details
200- on the coalescence and :ref:`agg-sort-skip-limit-sequence` for an
201- example.
202-
203- For aggregation operations on :doc:`sharded collections
204- <aggregation-pipeline-sharded-collections>`, this optimization reduces
205- the results returned from each shard.
206-
207- .. _agg-project-skip-limit-optimization:
208-
209- ``$project`` + ``$skip`` or ``$limit`` Sequence Optimization
210- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174+ ``$project`` + ``$skip`` Sequence Optimization
175+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
211176
212177.. versionadded:: 3.2
213178
214- When you have a sequence with :pipeline:`$project` followed by either
215- :pipeline:`$skip` or :pipeline:`$limit` , the :pipeline:`$skip` or
216- :pipeline:`$limit` moves before :pipeline:`$project`. For example, if
179+ When you have a sequence with :pipeline:`$project` followed by
180+ :pipeline:`$skip`, the :pipeline:`$skip`
181+ moves before :pipeline:`$project`. For example, if
217182the pipeline consists of the following stages:
218183
219184.. code-block:: javascript
220185
221186 { $sort: { age : -1 } },
222187 { $project: { status: 1, name: 1 } },
223- { $limit : 5 }
188+ { $skip : 5 }
224189
225190During the optimization phase, the optimizer transforms the sequence to
226191the following:
227192
228193.. code-block:: javascript
229194
230195 { $sort: { age : -1 } },
231- { $limit: 5 }
232- { $project: { status: 1, name: 1 } },
233-
234- This optimization allows for more opportunities for
235- :ref:`agg-sort-limit-coalescence`, such as with ``$sort`` + ``$limit``
236- sequences. See :ref:`agg-sort-limit-coalescence` for details on the
237- coalescence.
196+ { $skip: 5 },
197+ { $project: { status: 1, name: 1 } }
238198
239199.. _aggregation-pipeline-coalescence-optimization:
240200
@@ -250,14 +210,58 @@ reordering optimization.
250210``$sort`` + ``$limit`` Coalescence
251211~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
252212
253- When a :pipeline:`$sort` immediately precedes a :pipeline:`$limit`, the
254- optimizer can coalesce the :pipeline:`$limit` into the
255- :pipeline:`$sort`. This allows the sort operation to only maintain the
213+ .. versionchanged:: 4.0
214+
215+ When a :pipeline:`$sort` precedes a :pipeline:`$limit`, the optimizer
216+ can coalesce the :pipeline:`$limit` into the :pipeline:`$sort` if no
217+ intervening stages modify the number of documents
218+ (e.g. :pipeline:`$unwind`, :pipeline:`$group`).
219+ MongoDB will not coalesce the :pipeline:`$limit` into the
220+ :pipeline:`$sort` if there are pipeline stages that change the number of
221+ documents between the :pipeline:`$sort` and :pipeline:`$limit` stages..
222+
223+ For example, if the pipeline consists of the following stages:
224+
225+ .. code-block:: javascript
226+
227+ { $sort : { age : -1 } },
228+ { $project : { age : 1, status : 1, name : 1 } },
229+ { $limit: 5 }
230+
231+ During the optimization phase, the optimizer coalesces the sequence
232+ to the following:
233+
234+ .. code-block:: javascript
235+
236+ {
237+ "$sort" : {
238+ "sortKey" : {
239+ "age" : -1
240+ },
241+ "limit" : NumberLong(5)
242+ }
243+ },
244+ { "$project" : {
245+ "age" : 1,
246+ "status" : 1,
247+ "name" : 1
248+ }
249+ }
250+
251+ This allows the sort operation to only maintain the
256252top ``n`` results as it progresses, where ``n`` is the specified limit,
257253and MongoDB only needs to store ``n`` items in memory
258254[#coalescence-allowDiskUse]_. See :ref:`sort-and-memory` for more
259255information.
260256
257+ .. admonition:: Sequence Optimization with $skip
258+
259+ If there is a :pipeline:`$skip` stage between the :pipeline:`$sort`
260+ and :pipeline:`$limit` stages, MongoDB will coalesce the
261+ :pipeline:`$limit` into the :pipeline:`$sort` stage and increase the
262+ :pipeline:`$limit` value by the :pipeline:`$skip` amount. See
263+ :ref:`agg-sort-skip-limit-sequence` for an example.
264+
261265.. [#coalescence-allowDiskUse] The optimization will still apply when
262266 ``allowDiskUse`` is ``true`` and the ``n`` items exceed the
263267 :ref:`aggregation memory limit <agg-memory-restrictions>`.
@@ -378,13 +382,8 @@ option, the ``explain`` output shows the coalesced stage:
378382 }
379383 }
380384
381- Examples
382- --------
383-
384- The following examples are some sequences that can take advantage of
385- both sequence reordering and coalescence. Generally, coalescence occurs
386- *after* any sequence reordering optimization.
387-
385+ Example
386+ -------
388387.. _agg-sort-skip-limit-sequence:
389388
390389``$sort`` + ``$skip`` + ``$limit`` Sequence
@@ -399,60 +398,24 @@ A pipeline contains a sequence of :pipeline:`$sort` followed by a
399398 { $skip: 10 },
400399 { $limit: 5 }
401400
402- First, the optimizer performs the :ref:`agg-skip -limit-optimization ` to
401+ The optimizer performs :ref:`agg-sort -limit-coalescence ` to
403402transforms the sequence to the following:
404403
405404.. code-block:: javascript
406405
407- { $sort: { age : -1 } },
408- { $limit: 15 }
409- { $skip: 10 }
410-
411- The :ref:`agg-skip-limit-optimization` increases the :pipeline:`$limit`
412- amount with the reordering. See :ref:`agg-skip-limit-optimization` for
413- details.
414-
415- The reordered sequence now has :pipeline:`$sort` immediately preceding
416- the :pipeline:`$limit`, and the pipeline can coalesce the two stages to
417- decrease memory usage during the sort operation. See
418- :ref:`agg-sort-limit-coalescence` for more information.
419-
420- ``$limit`` + ``$skip`` + ``$limit`` + ``$skip`` Sequence
421- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
422-
423- A pipeline contains a sequence of alternating :pipeline:`$limit` and
424- :pipeline:`$skip` stages:
425-
426- .. code-block:: javascript
427-
428- { $limit: 100 },
429- { $skip: 5 },
430- { $limit: 10 },
431- { $skip: 2 }
432-
433- The :ref:`agg-skip-limit-optimization` reverses the position of the ``{
434- $skip: 5 }`` and ``{ $limit: 10 }`` stages and increases the limit
435- amount:
436-
437- .. code-block:: javascript
438-
439- { $limit: 100 },
440- { $limit: 15},
441- { $skip: 5 },
442- { $skip: 2 }
443-
444- The optimizer then coalesces the two :pipeline:`$limit` stages into a
445- single :pipeline:`$limit` stage and the two :pipeline:`$skip` stages
446- into a single :pipeline:`$skip` stage. The resulting sequence is the
447- following:
448-
449- .. code-block:: javascript
450-
451- { $limit: 15 },
452- { $skip: 7 }
406+ {
407+ "$sort" : {
408+ "sortKey" : {
409+ "age" : -1
410+ },
411+ "limit" : NumberLong(15)
412+ }
413+ },
414+ {
415+ "$skip" : NumberLong(10)
416+ }
453417
454- See :ref:`agg-limit-limit-coalescence` and
455- :ref:`agg-skip-skip-coalescence` for details.
418+ MongoDB increases the :pipeline:`$limit` amount with the reordering.
456419
457420.. seealso::
458421 :method:`explain <db.collection.aggregate()>` option in the
0 commit comments