Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs Menu
Docs Home
/ /
Operadores de pipeline de agregación

$topN (acumulador de agregación)

$topN

Nuevo en la versión 5.2.

Devuelve una agregación de los n elementos principales dentro de un grupo, de acuerdo con 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 debe ser una expresión entera positiva que sea constante o que dependa del valor de _id para $group.

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

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

  • $topN no filtra los valores nulos.

  • $topN convierte los valores faltantes a nulos, que se conservan en el resultado.

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 por gameId. Este ejemplo tiene solo un gameId, G1.

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

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

  • Debido al sortBy: { "score" : 1 }, los valores nulos se ordenan al principio del arreglo de playerId devueltos.

[
{
_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 el orden. Como ejemplo, consideremos una colección cuyos valores consisten en cadenas y números.

  • En una ordenación ascendente, los valores de string se ordenan después de los valores numéricos.

  • En una ordenación descendente, los valores de string 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 string "2".

  • PlayerC tiene un puntaje de string vacía.

Debido a que el ordenamiento es descendente { "score" : -1 }, los valores de literales de string se ordenan antes de la puntuación numérica de PlayerA:

[
{
_id: "G1",
playerId: [ [ "PlayerB", "2" ], [ "PlayerC", "" ], [ "PlayerA", 1 ] ]
}
]

$topN no es compatible como expresión de agregación.

$topN es compatible como un window operator.

Los grupos dentro del pipeline de agregación $topN están sujetos al límite de 100 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 }
])

Puede usar el acumulador $topN para encontrar a los jugadores con la puntuación más alta en un solo juego.

db.gamescores.aggregate( [
{
$match : { gameId : "G1" }
},
{
$group:
{
_id: "$gameId",
playerId:
{
$topN:
{
output: ["$playerId", "$score"],
sortBy: { "score": -1 },
n:3
}
}
}
}
] )

La pipeline de ejemplo:

  • Utiliza $match para filtrar los resultados en un solo gameId. En este caso, G1.

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

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

  • Especifica los campos que se producen de $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 usar el acumulador $topN para encontrar a los jugadores con mayor puntuación en cada partida.

db.gamescores.aggregate( [
{
$group:
{ _id: "$gameId", playerId:
{
$topN:
{
output: [ "$playerId","$score" ],
sortBy: { "score": -1 },
n: 3
}
}
}
}
] )

La pipeline de ejemplo:

  • Utiliza $group para agrupar los resultados por gameId.

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

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

  • Utiliza $topN para devolver los tres documentos principales con el más alto score 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 dinámicamente el valor de n. En este ejemplo, se utiliza la expresión $cond en el campo gameId.

db.gamescores.aggregate([
{
$group:
{
_id: {"gameId": "$gameId"},
gamescores:
{
$topN:
{
output: "$score",
n: { $cond: { if: {$eq: ["$gameId","G2"] }, then: 1, else: 3 } },
sortBy: { "score": -1 }
}
}
}
}
] )

La pipeline de ejemplo:

  • Utiliza $group para agrupar los resultados por gameId.

  • Especifica los campos que se producen de $topN con output : "$score".

  • Si el gameId es G2 entonces n es 1, de lo contrario n es 3.

  • Utiliza ordenación 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