Definition
Returns an aggregation of the top n elements within a group, according to the specified sort order. If the group contains fewer than n elements, $topN returns all elements in the group.
Note
Other Uses of $topN
This page describes $topN when used as an accumulator. Accumulators return an aggregated value across a group of input documents.
You can also use $topN in these other contexts:
$topN (window function), which returns the topnelements from documents in a particular window according to the specified sort order.$topN (expression), which returns the topnelements from an array.
Syntax
{ $topN: { n: <expression>, sortBy: { <field1>: <sort order>, <field2>: <sort order> ... }, output: <expression> } }
Field | Type | Description |
|---|---|---|
| Expression | Determines the maximum number of results returned per group. |
| Document | Specifies the order of results, with syntax similar to |
| Expression | Specifies the output for each element in the group. Can be any expression. |
Behavior
Null and Missing Values
$topNdoes not filter out null values.$topNconverts missing values to null which are preserved in the output.
db.aggregate( [ { $documents: [ { playerId: "PlayerA", gameId: "G1", score: 1 }, { playerId: "PlayerB", gameId: "G1", score: 2 }, { playerId: "PlayerC", gameId: "G1", score: 3 }, { playerId: "PlayerD", gameId: "G1"}, { playerId: "PlayerE", gameId: "G1", score: null } ] }, { $group: { _id: "$gameId", playerId: { $topN: { output: [ "$playerId", "$score" ], sortBy: { "score": 1 }, n: 3 } } } } ] )
In this example:
$documentscreates the literal documents that contain player scores.$groupgroups the documents bygameId. This example has only onegameId,G1.PlayerDhas a missing score andPlayerEhas a nullscore. These values are both considered as null.The
playerIdandscorefields are specified asoutput : ["$playerId"," $score"]and returned as array values.Because of the
sortBy: { "score" : 1 }, the null values are sorted to the front of the returnedplayerIdarray.
[ { _id: 'G1', playerId: [ [ 'PlayerD', null ], [ 'PlayerE', null ], [ 'PlayerA', 1 ] ] } ]
BSON Data Type Sort Ordering
When sorting different types, the order of BSON data types is used to determine ordering. As an example, consider a collection whose values consist of strings and numbers.
In an ascending sort, string values are sorted after numeric values.
In a descending sort, string values are sorted before numeric values.
db.aggregate( [ { $documents: [ { playerId: "PlayerA", gameId: "G1", score: 1 }, { playerId: "PlayerB", gameId: "G1", score: "2" }, { playerId: "PlayerC", gameId: "G1", score: "" } ] }, { $group: { _id: "$gameId", playerId: { $topN: { output: ["$playerId","$score"], sortBy: {"score": -1}, n: 3 } } } } ] )
In this example:
PlayerAhas an integer score.PlayerBhas a string"2"score.PlayerChas an empty string score.
Because the sort is in descending { "score" : -1 }, the string literal values are sorted before PlayerA's numeric score:
[ { _id: "G1", playerId: [ [ "PlayerB", "2" ], [ "PlayerC", "" ], [ "PlayerA", 1 ] ] } ]
Examples
The examples on this page use data from the sample_mflix dataset. For details on how to load this dataset into your self-managed MongoDB deployment, see Load the Sample Dataset. If you made any modifications to the sample databases, you may need to drop and recreate the databases to run the examples on this page.
Find the Three Highest-Rated Movies in a Single Genre
You can use the $topN accumulator to find the three highest-rated movies in the Short genre.
db.movies.aggregate( [ { $match: { genres: "Short", "imdb.rating": { $gt: 0 } } }, { $group: { _id: "Short", topRatedMovies: { $topN: { output: [ "$title", "$imdb.rating" ], sortBy: { "imdb.rating": -1, title: 1 }, n: 3 } } } } ] )
The example pipeline:
Uses
$matchto restrict the input toShortmovies that include animdb.ratingvalue.Uses
$groupto place the matched movies into a singleShortgroup.Uses
sortBy: { "imdb.rating": -1, title: 1 }to rank movies by rating and usetitleas a tie-breaker.Specifies the fields returned by
$topNwithoutput: [ "$title", "$imdb.rating" ].Uses
$topNto return the top three matching movies withn: 3.
Find the Highest-Rated Movies for Each Genre
You can use the $topN accumulator to find the highest-rated movies for each genre.
db.movies.aggregate( [ { $unwind: "$genres" }, { $match: { "imdb.rating": { $gt: 0 } } }, { $group: { _id: "$genres", topRatedMovies: { $topN: { output: [ "$title", "$imdb.rating" ], sortBy: { "imdb.rating": -1, title: 1 }, n: 3 } } } }, { $sort: { _id: 1 } }, { $limit: 5 } ] )
The example pipeline:
Uses
$unwindto expand each movie'sgenresarray.Uses
$matchto keep only documents that include animdb.ratingvalue.Uses
$groupto group the results by genre.Specifies the fields returned by
$topNwithoutput: [ "$title", "$imdb.rating" ].Uses
sortBy: { "imdb.rating": -1, title: 1 }to rank movies by rating and usetitleas a deterministic tie-breaker.Uses
$topNto return the top three movies for each genre withn: 3.
Set n Dynamically Based on the Group Key
You can assign the value of n dynamically. The following example uses the $cond expression to return different numbers of movies based on content rating.
db.movies.aggregate( [ { $match: { rated: { $in: [ "G", "PG", "PG-13", "R" ] }, "imdb.rating": { $gt: 0 } } }, { $group: { _id: { rated: "$rated" }, movies: { $topN: { output: { title: "$title", rating: "$imdb.rating" }, n: { $cond: { if: { $eq: [ "$rated", "PG" ] }, then: 3, else: 1 } }, sortBy: { "imdb.rating": -1 } } } } }, { $sort: { "_id.rated": 1 } } ] )
The example pipeline:
Uses
$matchto keep only movies withG,PG,PG-13, orRcontent ratings that include animdb.ratingvalue.Uses
$groupto group the results by content rating with_id: { rated: "$rated" }.Specifies the fields returned by
$topNwithoutput: { title: "$title", rating: "$imdb.rating" }.If the content rating is
PGthennis 3. Otherwise,nis 1.Uses
sortBy: { "imdb.rating": -1 }to find the topnmovies based on IMDb score.Sorts the results by content rating in alphabetical order.