Docs Menu
Docs Home
/ /

$topN (acumulador de agregación)

$topN

Nuevo en la versión 5.2.

Devuelve una agregación de los n primeros elementos de un grupo, según el orden de clasificación especificado. Si el grupo contiene menos de n elementos, $topN devuelve todos los elementos del grupo.

{
$topN:
{
n: <expression>,
sortBy: { <field1>: <sort order>, <field2>: <sort order> ... },
output: <expression>
}
}
  • n limita el número de resultados por grupo y tiene que ser una expresión integral positiva que sea una constante o dependa del valor _id para $group.

  • sortBy especifica el orden de los resultados, con una sintaxis similar $sort a.

  • output representa la salida de cada elemento del grupo y puede ser cualquier expresión.

  • $topN no filtra valores nulos.

  • $topN Convierte 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:

  • $documents crea los documentos literales que contienen las puntuaciones de los jugadores.

  • $group agrupa los documentos gameId por. Este ejemplo solo tiene un,.gameIdG1

  • PlayerD tiene una puntuación faltante y PlayerE tiene un valor nulo score. Ambos valores se consideran nulos.

  • Los campos playerId y score se especifican como output : ["$playerId"," $score"] y se devuelven como valores de matriz.

  • Debido a sortBy: { "score" : 1 }, los valores nulos se ordenan al frente de la matriz playerId devuelta.

[
{
_id: 'G1',
playerId: [ [ 'PlayerD', null ], [ 'PlayerE', null ], [ 'PlayerA', 1 ] ]
}
]

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:

  • PlayerA tiene una puntuación entera.

  • PlayerB tiene una puntuación de cadena "2".

  • PlayerC tiene 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 ] ]
}
]

$topN no se admite como expresión de agregación.

$topN se admite window operator como.

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.

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 }
])

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.gameId En esteG1 caso,.

  • Usa para agrupar los $group resultados gameId por. En esteG1 caso,.

  • Utiliza ordenar por { "score": -1 } para ordenar los resultados en orden descendente.

  • Especifica los campos que se generan desde $topN con output : ["$playerId"," $score"].

  • Utiliza $topN para devolver los tres documentos principales con el score más alto para el juego G1 con n : 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

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 $group para agrupar los resultados por gameId.

  • Especifica los campos que se generan desde $topN con output : ["$playerId", "$score"].

  • Utiliza ordenar por { "score": -1 } para ordenar los resultados en orden descendente.

  • Utiliza $topN para devolver los tres documentos principales con el score más alto para cada juego con n: 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

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 $group para agrupar los resultados por gameId.

  • Especifica los campos que se generan desde $topN con output : "$score".

  • Si gameId es G2 entonces n es 1, de lo contrario n es 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 ] }
]

Volver

$top

En esta página