Docs Menu

bottomN(์ง‘๊ณ„ ๋ˆ„์‚ฐ๊ธฐ)

$bottomN

๋ฒ„์ „ 5.2์— ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ง€์ •๋œ ์ •๋ ฌ ์ˆœ์„œ์— ๋”ฐ๋ผ ๊ทธ๋ฃน ๋‚ด ํ•˜์œ„ n ๊ฐœ ์š”์†Œ์˜ ์• ๊ทธ๋ฆฌ๊ฒŒ์ด์…˜์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฃน์— n ๊ฐœ ๋ฏธ๋งŒ์˜ ์š”์†Œ๊ฐ€ ํฌํ•จ๋œ ๊ฒฝ์šฐ $bottomN ์€ ๊ทธ๋ฃน์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

{
$bottomN:
{
n: <expression>,
sortBy: { <field1>: <sort order>, <field2>: <sort order> ... },
output: <expression>
}
}
  • $bottomN ์€ null ๊ฐ’์„ ํ•„ํ„ฐํ•˜๋‹ค ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • $bottomN ์€ ๋ˆ„๋ฝ๋œ ๊ฐ’์„ ์ถœ๋ ฅ์— ๋ณด์กด๋˜๋Š” null๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

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:
{
$bottomN:
{
output: [ "$playerId", "$score" ],
sortBy: { "score": -1 },
n: 3
}
}
}
}
] )

์ด ์˜ˆ์‹œ์—์„œ๋Š”

  • $documents ๋Š” ํ”Œ๋ ˆ์ด์–ด ์ ์ˆ˜๊ฐ€ ํฌํ•จ๋œ ๋ฆฌํ„ฐ๋Ÿด ๋ฌธ์„œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • $group์€ gameId ๊ธฐ์ค€์œผ๋กœ ๋ฌธ์„œ๋ฅผ ๊ทธ๋ฃนํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์‹œ์—๋Š” gameId๊ฐ€ ๋‹จ ํ•˜๋‚˜(G1)๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค.

  • PlayerD์—๋Š” ๋ˆ„๋ฝ๋œ ์ ์ˆ˜๊ฐ€ ์žˆ๊ณ  PlayerE์—๋Š” null score์ด(๊ฐ€) ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ ๋ชจ๋‘ 'null'๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.

  • playerId ๋ฐ score ํ•„๋“œ๋Š” output : ["$playerId"," $score"]๋กœ ์ง€์ •๋˜๊ณ  ๋ฐฐ์—ด ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

  • sortBy: { "score" : -1 } ๋•Œ๋ฌธ์— null ๊ฐ’์€ ๋ฐ˜ํ™˜๋œ playerId ๋ฐฐ์—ด์˜ ๋์œผ๋กœ ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค.

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

์„œ๋กœ ๋‹ค๋ฅธ ์œ ํ˜•์„ ์ •๋ ฌํ•  ๋•Œ BSON ๋ฐ์ดํ„ฐ ์œ ํ˜• ์˜ ์ˆœ์„œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆœ์„œ๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๊ฐ’์ด ๋ฌธ์ž์—ด๊ณผ ์ˆซ์ž๋กœ ๊ตฌ์„ฑ๋œ ์ปฌ๋ ‰์…˜์„ ์ƒ๊ฐํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ์—์„œ๋Š” ๋ฌธ์ž์—ด ๊ฐ’์ด ์ˆซ์ž ๊ฐ’ ๋’ค์— ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค.

  • ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ์—์„œ๋Š” ๋ฌธ์ž์—ด ๊ฐ’์ด ์ˆซ์ž ๊ฐ’๋ณด๋‹ค ๋จผ์ € ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค.

db.aggregate( [
{
$documents: [
{ playerId: "PlayerA", gameId: "G1", score: 1 },
{ playerId: "PlayerB", gameId: "G1", score: "2" },
{ playerId: "PlayerC", gameId: "G1", score: "" }
]
},
{
$group:
{
_id: "$gameId",
playerId: {
$bottomN:
{
output: ["$playerId","$score"],
sortBy: {"score": -1},
n: 3
}
}
}
}
] )

์ด ์˜ˆ์‹œ์—์„œ๋Š”

  • PlayerA ์—๋Š” ์ •์ˆ˜ ์ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • PlayerB ์— ๋ฌธ์ž์—ด "2" ์ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • PlayerC ์— ๋นˆ string ์ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ •๋ ฌ์ด { "score" : -1 } ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’์€ PlayerA ์˜ ์ˆซ์ž ์ ์ˆ˜๋ณด๋‹ค ๋จผ์ € ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค.

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

$bottomN์€(๋Š”) ์ง‘๊ณ„ ํ‘œํ˜„์‹์œผ๋กœ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

$bottomN์€(๋Š”) window operator(์œผ)๋กœ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

$bottomN ์ง‘๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ ๋‚ด์˜ ๊ทธ๋ฃน์—๋Š” 100MB ์ œํ•œ ํŒŒ์ดํ”„๋ผ์ธ ์ œํ•œ์ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ณ„ ๊ทธ๋ฃน์— ๋Œ€ํ•ด ์ด ์ œํ•œ์„ ์ดˆ๊ณผํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด์„œ ์• ๊ทธ๋ฆฌ๊ฒŒ์ด์…˜์ด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ฌธ์„œ๊ฐ€ ํฌํ•จ๋œ gamescores collection์„ ์ƒ๊ฐํ•ด ๋ณด์„ธ์š”.

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

$bottomN ์ถ•์ ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์ผ ๊ฒŒ์ž„์—์„œ ๊ฐ€์žฅ ๋‚ฎ์€ ์ ์ˆ˜๋ฅผ ๋ฐ›์€ ํ”Œ๋ ˆ์ด์–ด๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์˜ˆ์‹œ ํŒŒ์ดํ”„๋ผ์ธ:

  • $match๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์ผ gameId ๊ฒฐ๊ณผ๋ฅผ ํ•„ํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” G1์ž…๋‹ˆ๋‹ค.

  • $group์„ ์‚ฌ์šฉํ•˜์—ฌ gameId๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋ฃนํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” G1์ž…๋‹ˆ๋‹ค.

  • { "score": -1 } ๊ธฐ์ค€ ์ •๋ ฌ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

  • $bottomN ์—์„œ output : ["$playerId"," $score"] ๋กœ ์ถœ๋ ฅ๋˜๋Š” ํ•„๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • $bottomN ์„ ์‚ฌ์šฉํ•˜์—ฌ n : 3 ๊ฐ€ ์žˆ๋Š” G1 ๊ฒŒ์ž„์—์„œ ๊ฐ€์žฅ ๋‚ฎ์€ score ๋ฅผ ๊ฐ€์ง„ ํ•˜์œ„ ์„ธ ๋ฌธ์„œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด ์—ฐ์‚ฐ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

[
{
_id: "G1",
playerId: [ [ "PlayerB", 33 ], [ "PlayerA", 31 ], [ "PlayerD", 1 ] ]
}
]

์ด ์ฟผ๋ฆฌ์™€ ๋™์ผํ•œ SQL:

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) AS T3
ON GS.GAMEID = T3.GAMEID
GROUP BY T3.GAMEID,T3.PLAYERID,T3.SCORE
ORDER BY T3.SCORE DESC

$bottomN ์ถ•์ ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ๊ฒŒ์ž„์—์„œ ๊ฐ€์žฅ ๋‚ฎ์€ ์ ์ˆ˜๋ฅผ ๋ฐ›์€ ํ”Œ๋ ˆ์ด์–ด๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์˜ˆ์‹œ ํŒŒ์ดํ”„๋ผ์ธ:

  • $group์„ ์‚ฌ์šฉํ•˜์—ฌ gameId๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋ฃนํ™”ํ•ฉ๋‹ˆ๋‹ค.

  • $bottomN ์—์„œ output : ["$playerId", "$score"] ๋กœ ์ถœ๋ ฅ๋˜๋Š” ํ•„๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • { "score": -1 } ๊ธฐ์ค€ ์ •๋ ฌ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

  • $bottomN ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ๊ฒŒ์ž„์—์„œ ๊ฐ€์žฅ ๋‚ฎ์€ score ๋ฅผ ๊ฐ€์ง„ ํ•˜์œ„ ์„ธ ๋ฌธ์„œ๋ฅผ n: 3 ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด ์—ฐ์‚ฐ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

[
{
_id: "G1",
playerId: [ [ "PlayerB", 33 ], [ "PlayerA", 31 ], [ "PlayerD", 1 ] ]
},
{
_id: "G2",
playerId: [ [ "PlayerC", 66 ], [ "PlayerB", 14 ], [ "PlayerA", 10 ] ]
}
]

์ด ์ฟผ๋ฆฌ์™€ ๋™์ผํ•œ SQL:

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 >= 2
ORDER BY GAMEID

n ์˜ ๊ฐ’์„ ๋™์ ์œผ๋กœ ํ• ๋‹นํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” $cond ํ‘œํ˜„์‹์ด gameId ํ•„๋“œ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

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

์˜ˆ์‹œ ํŒŒ์ดํ”„๋ผ์ธ:

  • $group ์„ ์‚ฌ์šฉํ•˜์—ฌ gameId ์„ ๊ธฐ์ค€์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋ฃนํ™”ํ•ฉ๋‹ˆ๋‹ค.

  • $bottomN ์—์„œ output : "$score" ๋กœ ์ถœ๋ ฅ๋˜๋Š” ํ•„๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • gameId ๊ฐ€ G2 ์ด๋ฉด n ๋Š” 1์ด๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด n ๋Š” 3์ž…๋‹ˆ๋‹ค.

  • { "score": -1 } ๊ธฐ์ค€ ์ •๋ ฌ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

์ด ์—ฐ์‚ฐ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

[
{ _id: { gameId: "G2" }, gamescores: [ 10 ] },
{ _id: { gameId: "G1" }, gamescores: [ 33, 31, 1 ] }
]