Definición
Sintaxis
{ $topN: { n: <expression>, sortBy: { <field1>: <sort order>, <field2>: <sort order> ... }, output: <expression> } }
nlimita el número de resultados por grupo y tiene que ser una expresión integral positiva que sea una constante o dependa del valor_idpara$group.sortBy especifica el orden de los resultados, con una sintaxis similar
$sorta.outputrepresenta la salida de cada elemento del grupo y puede ser cualquier expresión.
Comportamiento
Valores nulos y faltantes
$topNno filtra valores nulos.$topNConvierte los valores faltantes en nulos, que se conservan en la salida.
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 } } } } ] )
En este ejemplo:
$documentscrea los documentos literales que contienen las puntuaciones de los jugadores.$groupagrupa los documentosgameIdpor. Este ejemplo solo tiene un,.gameIdG1PlayerDtiene una puntuación faltante yPlayerEtiene un valor nuloscore. Ambos valores se consideran nulos.Los campos
playerIdyscorese especifican comooutput : ["$playerId"," $score"]y se devuelven como valores de matriz.Debido a
sortBy: { "score" : 1 }, los valores nulos se ordenan al frente de la matrizplayerIddevuelta.
[ { _id: 'G1', playerId: [ [ 'PlayerD', null ], [ 'PlayerE', null ], [ 'PlayerA', 1 ] ] } ]
Ordenamiento de tipos de datos BSON
Al ordenar diferentes tipos, se utiliza el orden de los tipos de datos BSON para determinar la ordenación. Por ejemplo, considere una colección cuyos valores consisten en cadenas y números.
En una ordenación ascendente, los valores de cadena se ordenan después de los valores numéricos.
En una ordenación descendente, los valores de cadena se ordenan antes que los valores numéricos.
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 } } } } ] )
En este ejemplo:
PlayerAtiene una puntuación entera.PlayerBtiene una puntuación de cadena"2".PlayerCtiene una partitura de cuerda vacía.
Debido a que la clasificación se realiza en orden descendente { "score" : -1 }, los valores literales de cadena se ordenan antes que la puntuación numérica de PlayerA:
[ { _id: "G1", playerId: [ [ "PlayerB", "2" ], [ "PlayerC", "" ], [ "PlayerA", 1 ] ] } ]
Restricciones
Compatibilidad con funciones de ventana y expresiones de agregación
$topN no se admite como expresión de agregación.
$topN se admite window operator como.
Consideraciones sobre el límite de memoria
Los grupos dentro del $topN flujo de agregación están sujetos al 100 límite de MB. Si se supera este límite para un grupo individual, la agregación falla con un error.
Ejemplos
Considera una colección gamescores con los siguientes documentos:
db.gamescores.insertMany([ { playerId: "PlayerA", gameId: "G1", score: 31 }, { playerId: "PlayerB", gameId: "G1", score: 33 }, { playerId: "PlayerC", gameId: "G1", score: 99 }, { playerId: "PlayerD", gameId: "G1", score: 1 }, { playerId: "PlayerA", gameId: "G2", score: 10 }, { playerId: "PlayerB", gameId: "G2", score: 14 }, { playerId: "PlayerC", gameId: "G2", score: 66 }, { playerId: "PlayerD", gameId: "G2", score: 80 } ])
Encuentra los tres más altos Scores
Puedes utilizar el acumulador $topN para encontrar los jugadores con mayor puntuación en un solo juego.
db.gamescores.aggregate( [ { $match : { gameId : "G1" } }, { $group: { _id: "$gameId", playerId: { $topN: { output: ["$playerId", "$score"], sortBy: { "score": -1 }, n:3 } } } } ] )
El ejemplo de canalización:
Utiliza para filtrar los resultados según un
$matchúnico.gameIdEn esteG1caso,.Usa para agrupar los
$groupresultadosgameIdpor. En esteG1caso,.Utiliza ordenar por
{ "score": -1 }para ordenar los resultados en orden descendente.Especifica los campos que se generan desde
$topNconoutput : ["$playerId"," $score"].Utiliza
$topNpara devolver los tres documentos principales con elscoremás alto para el juegoG1conn : 3.
La operación devuelve los siguientes resultados:
[ { _id: 'G1', playerId: [ [ 'PlayerC', 99 ], [ 'PlayerB', 33 ], [ 'PlayerA', 31 ] ] } ]
El equivalente en SQL para esta query es:
SELECT T3.GAMEID,T3.PLAYERID,T3.SCORE FROM GAMESCORES AS GS JOIN (SELECT TOP 3 GAMEID,PLAYERID,SCORE FROM GAMESCORES WHERE GAMEID = 'G1' ORDER BY SCORE DESC) AS T3 ON GS.GAMEID = T3.GAMEID GROUP BY T3.GAMEID,T3.PLAYERID,T3.SCORE ORDER BY T3.SCORE DESC
Encontrar los tres documentos con la puntuación más alta en varios juegos
Puedes utilizar el acumulador $topN para encontrar los jugadores con mayor puntuación en cada juego.
db.gamescores.aggregate( [ { $group: { _id: "$gameId", playerId: { $topN: { output: [ "$playerId","$score" ], sortBy: { "score": -1 }, n: 3 } } } } ] )
El ejemplo de canalización:
Utiliza
$grouppara agrupar los resultados porgameId.Especifica los campos que se generan desde
$topNconoutput : ["$playerId", "$score"].Utiliza ordenar por
{ "score": -1 }para ordenar los resultados en orden descendente.Utiliza
$topNpara devolver los tres documentos principales con elscoremás alto para cada juego conn: 3.
La operación devuelve los siguientes resultados:
[ { _id: 'G1', playerId: [ [ 'PlayerC', 99 ], [ 'PlayerB', 33 ], [ 'PlayerA', 31 ] ] }, { _id: 'G2', playerId: [ [ 'PlayerD', 80 ], [ 'PlayerC', 66 ], [ 'PlayerB', 14 ] ] } ]
El equivalente en SQL para esta query es:
SELECT PLAYERID,GAMEID,SCORE FROM( SELECT ROW_NUMBER() OVER (PARTITION BY GAMEID ORDER BY SCORE DESC) AS GAMERANK, GAMEID,PLAYERID,SCORE FROM GAMESCORES ) AS T WHERE GAMERANK <= 3 ORDER BY GAMEID
Cálculo n de según la clave de grupo para $group
También puede asignar el valor n dinámicamente. En este ejemplo,$cond se utiliza la expresión en el gameId campo.
db.gamescores.aggregate([ { $group: { _id: {"gameId": "$gameId"}, gamescores: { $topN: { output: "$score", n: { $cond: { if: {$eq: ["$gameId","G2"] }, then: 1, else: 3 } }, sortBy: { "score": -1 } } } } } ] )
El ejemplo de canalización:
Utiliza
$grouppara agrupar los resultados porgameId.Especifica los campos que se generan desde
$topNconoutput : "$score".Si
gameIdesG2entoncesnes 1, de lo contrariones 3.Utiliza ordenar por
{ "score": -1 }para ordenar los resultados en orden descendente.
La operación devuelve los siguientes resultados:
[ { _id: { gameId: 'G1' }, gamescores: [ 99, 33, 31 ] }, { _id: { gameId: 'G2' }, gamescores: [ 80 ] } ]