Uh oh!
There was an error while loading. Please reload this page.
Document six missing aggregation pipeline stages - #64
Merged
guanzhousongmicrosoft merged 4 commits intoAug 3, 2026
Conversation
Add documentation for aggregation stages that are implemented in DocumentDB but were missing from the docs: - $project — field inclusion/exclusion and expression projection - $setWindowFields — window functions with partitioning - $graphLookup — recursive graph traversal - $replaceRoot — promote subdocument to top level - $unionWith — combine pipeline results (UNION ALL) - $vectorSearch — approximate nearest neighbor search - $limit — restrict output document count - $count — count documents in pipeline - $currentOp — admin operation metadata - $search — text search stage Each doc follows the existing format: YAML frontmatter, syntax block, parameters table, examples, and key takeaways. Validated against the C source in bson_aggregation_pipeline.c for accuracy. Signed-off-by: richardsimmonds <richardsimmonds314@gmail.com>
Rebasing this branch onto main will conflict: $graphLookup, $limit, $project, and $vectorSearch were all documented in documentdb#59 while this pull request was open, so those four files are add/add conflicts against pages that already exist. Removed them here. The remaining six stages are still missing from the reference and are what this branch adds. $search needed more than a rebase - it documents the wrong feature. The page describes full-text search over a text index, with an example built on a text operator: $search: { text: { query: "Beverage", path: "name" } } DocumentDB's $search is a vector search stage. Its operator registry has exactly two entries, cosmosSearch and knnBeta (deprecated), both vector operators, and there is no text operator anywhere in the search sources. The example above does not return no results - it fails outright with "Unrecognized $search option: text", and the page's stated requirement of a text index points at the wrong index type entirely. Rewritten against the stage's actual parsing: the two operators, the options carried alongside them (index, count, returnStoredSource), and the operator spec itself (path, vector, k, filter, exact, oversampling, score), including which of those knnBeta rejects and which require server-side pre-filtering to be enabled. count is documented as having no observable effect, since the engine parses it but does not yet emit the metadata. The page now points at $vectorSearch as the stage to prefer for new queries, and notes $text as the answer for the full-text case the original page was reaching for. The other five pages were checked against the engine and left alone. $currentOp in particular is accurate: its five options are real, and its first-stage and admin-database requirements match the handler.
Two review comments that were fixable from the source. $setWindowFields showed a syntax template with no valid instantiation: documents, range, and unit all appear inside one window block, and that combination is rejected. EnsureValidWindowSpec accepts either documents alone, or range with an optional unit, and nothing else - documents and range together throw "Window bounds may only define either 'documents' or 'unit', but never both", and a window carrying neither throws a message naming the two valid shapes. The template now shows the choice, and both errors are quoted so a reader who hits one can map it back. The sortBy row said "Optional" without qualification, which is true of the parser and misleading everywhere else. EnsureSortRequirements requires exactly one ascending sort field for a range window - so the -1 the row endorsed cannot be used with one - and requires a sort field for any bounded document window, omissible only when the window is unbounded at both ends. Several operators require their own, some non-compound, and $shift requires one unconditionally. Added a table covering the three cases with the error each raises. $count claimed equivalence with $group plus $project. The two agree whenever a document reaches the stage, and diverge on empty input: HandleCountCore sets hasAggs without a groupClause, making an ungrouped aggregate that always produces a row, so $count returns zero where $group returns nothing. That distinction is the reason to reach for $count, so it is now stated rather than flattened into an equivalence - and it no longer contradicts the bullet directly above it.
…nsistent Closes the last two review threads without needing the stores dataset. $count duplicated accumulators/$count.md, which already documents the stage across 392 lines including the same $unwind example, and the two disagreed on the collection size. Removed the new page rather than relocating the old one: the stage stays documented, no inbound link breaks, and the repo stops carrying two pages with the same title. If the reference should instead file $count under aggregation with the stages, that is a move of the existing page and belongs in its own change. Removing it also takes with it the promotionEvents example, which unwound a field absent from that page's own sample document. The $replaceRoot examples ended in $limit: 2 while showing a single document. The count was the error, not the document - both outputs are one document from the canonical dataset - so the limit now matches what is shown. Setting it to 1 makes each example true by inspection instead of depending on how many documents the collection happens to hold, which is what made the original wrong. The remaining $limit-bearing examples, all in $setWindowFields, print no output blocks and so had nothing to contradict.
guanzhousongmicrosoft
approved these changes
Aug 3, 2026
guanzhousongmicrosoft
left a comment
Contributor
There was a problem hiding this comment.
Approving. The six pages fill a real gap, and the claims on the rewritten pages are derived from the engine source rather than from MongoDB's documentation - which is what the original divergences came from. Credit to @richardsimmonds for the original work in #47.
guanzhousongmicrosoft pushed a commit
that referenced
this pull request
Aug 3, 2026
Seventeen links across six pages point at relative .md paths and every one of them 404s. On $search the link to $vectorSearch renders as href="./%24vectorsearch.md", which resolves against the page's own directory - documentdb.io serves these with a trailing slash - and lands at /operators/aggregation/$search/%24vectorsearch.md. Wrong depth and a leaked extension, the two failure modes #57 catalogued, in the same href. They were introduced together. $vectorSearch, $project, $limit and $graphLookup arrived in #59, $search in #64 following the convention it found on the page next to it, and $meta links back to $vectorSearch the same way. None of them render, so the pages read as cross-linked while every cross-link is dead. Rewritten to the absolute form the rest of the reference already uses - https://documentdb.io/docs/reference/operators/aggregation/%24bucket/ - which is what #57 settled on for exactly this reason: it does not depend on how the site resolves a relative path, and it survives a page moving between directories. All thirteen distinct targets were requested against the live site and return 200, and no relative .md link remains anywhere in the repository.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Continues @richardsimmonds' work in #47, which this supersedes. His original commit is preserved in this branch's history; the reference gap it identified was real, and six stages that were missing are documented here.
What this adds
$currentOp,$replaceRoot,$search,$setWindowFields, and$unionWith— five stages with no reference page today.What changed from #47
Four files dropped.
$graphLookup,$limit,$project, and$vectorSearchwere documented in #59 while #47 was open, and were add/add conflicts against pages that now exist.$searchrewritten. The page documented Atlas-style full-text search over a text index. DocumentDB's$searchis a vector search stage —SearchOperatorsList[]holds exactlycosmosSearchandknnBeta(deprecated), and there is notextoperator in the search sources, so the original example failed withUnrecognized $search option: textrather than returning nothing. Rewritten against the stage's parsing: both operators, the options carried alongside them (index,count,returnStoredSource), and the operator spec (path,vector,k,filter,exact,oversampling,score), including which fieldsknnBetarejects and which need server-side pre-filtering.countis noted as having no observable effect, since the engine parses it but does not yet emit the metadata.$setWindowFieldscorrected. The syntax template putdocuments,range, andunitin onewindowblock, a combinationEnsureValidWindowSpecrejects; it now shows them as the alternatives they are, with both parse errors quoted.sortBywas described as plainly optional — arangewindow requires a single ascending sort field (so the-1the table endorsed cannot be used with one), a boundeddocumentswindow requires one, and several operators require their own. Added as a table with the error each case raises.$countdropped. It duplicatedaccumulators/$count.md, which already documents the stage including the same$unwindexample, and the two disagreed on collection size. Removing the new page keeps the stage documented and ends the duplicate title. Filing$countunderaggregation/instead would be a move of the existing page, and belongs in its own change.$replaceRootexamples made self-consistent. Both ended in{ $limit: 2 }while showing a single document. The count was the error, so the limit now matches the output — true by inspection rather than dependent on collection size, which is what made the originals wrong.Verification
Claims on the rewritten and corrected pages were derived from the engine source rather than from MongoDB's documentation, which is how the original divergences arose — everything wrong in #47 was accurate for MongoDB or Atlas.
$currentOpwas checked and left alone: its five options are real and its first-stage and admin-database requirements match the handler.