文章目录
- [MongoDB聚合运算符:lastN](#MongoDB聚合运算符:lastN)
-
- 语法
- 使用
-
- 空值或缺失值的处理
- [l a s t N 与 lastN与 lastN与bottomN对比](#l a s t N 与 lastN与 lastN与bottomN对比)
- 关于窗口功能和聚合表达式的支持
- 内存限制
- 举例
-
- 查找单场比赛的后三名运动员得分
- 查找多场比赛中后三名运动员的得分
- [s o r t 与 sort与 sort与lastN一起使用](#s o r t 与 sort与 sort与lastN一起使用)
- 根据group的键计算n
- [在聚合表达式中使用lastN](#在聚合表达式中使用lastN)
MongoDB聚合运算符:$lastN
$lastN聚合运算符返回分组中后n个元素的聚合,只有在分组元素是有序的情况下才有意义,如果分组中的元素个数小于n,将返回分组中所有的元素。
语法
js
{
$lastN:
{
input: <expression>,
n: <expression>
}
}
input指定要从文档中获取的字段或表达式值,可以是任何表达式nn 必须是正整数表达式,可以是常量,也可以是$group的_id值。
使用
空值或缺失值的处理
$lastN不会过滤掉空值- 缺失的值会被
$lastN转换为null
下面的聚合返回每个分组的最后5个文档:
js
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",
firstFiveScores:
{
$lastN:
{
input: "$score",
n: 5
}
}
}
}
] )
在这个示例中:
documents创建了一些包含运动员得分的字面量文档$group对文档按照gameId对文档进行分组,本例中只有一个gameId:G1PlayerD的得分得分不存在,PlayerE的得分为null,这两者的值都为都会被认为是nullinput: "$score"指定给firstFiveScores字段并返回一个数组- 由于没有排序标准,因此返回后5个分数字段
js
[
{
_id: 'G1',
firstFiveScores: [ 1, 2, 3, null, null ]
}
]
l a s t N 与 lastN与 lastN与bottomN对比
$lastN和$bottomN运算符返回的结果类似,但是:
- 如果文档来自于
$group且已经排序,应该使用$lastN - 如果要排序并且返回后n个元素,使用
$bottomN一个运算就可以搞定 $lastN可以用于聚合表达式,但是$bottomN不可以
关于窗口功能和聚合表达式的支持
$lastN支持作为聚合表达式$lastN同时支持作为窗口操作符
内存限制
调用$lastN的聚合管道受100MB的限制,如果单个组超出此限制,聚合将失败并返回错误。
举例
使用下面的脚本创建gamescores集合:
js
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 }
])
查找单场比赛的后三名运动员得分
使用$lastN单场比赛的前三名得分:
js
db.gamescores.aggregate( [
{
$match : { gameId : "G1" }
},
{
$group:
{
_id: "$gameId",
firstThreeScores:
{
$lastN:
{
input: ["$playerId", "$score"],
n:3
}
}
}
}
] )
在本例中:
- 使用
match过滤出gameId为G1的文档 - 使用
$group按照gameId进行分组 - 使用
output : ["$playerId"," $score"].为$lastN指定输入字段 - 使用
$lastN指定n:3返回G1游戏后三个文档
操作返回的结果如下:
js
[
{
_id: "G1",
lastThreeScores: [ [ "PlayerB", 33 ], [ "PlayerC", 99 ], [ "PlayerD", 1 ] ]
}
]
查找多场比赛中后三名运动员的得分
使用$lastN查找每个比赛中前n个输入字段:
js
db.gamescores.aggregate( [
{
$group:
{
_id: "$gameId", playerId:
{
$lastN:
{
input: [ "$playerId","$score" ],
n: 3
}
}
}
}
] )
在本例聚合管道中:
- 使用
$group根据gameId进行分组 - 使用
$lastN和n:3返回比赛前三个文档 - 为
$lastN指定输入字段input : ["$playerId", "$score"]
操作返回下面的结果:
js
[
{
_id: 'G2',
playerId: [ [ 'PlayerB', 14 ], [ 'PlayerC', 66 ], [ 'PlayerD', 80 ] ]
},
{
_id: 'G1',
playerId: [ [ 'PlayerB', 33 ], [ 'PlayerC', 99 ], [ 'PlayerD', 1 ] ]
}
]
s o r t 与 sort与 sort与lastN一起使用
在管道中较早使用$sort阶段可能会影响$lastN
js
db.gamescores.aggregate( [
{ $sort : { score : -1 } },
{
$group:
{ _id: "$gameId", playerId:
{
$lastN:
{
input: [ "$playerId","$score" ],
n: 3
}
}
}
}
] )
在这个例子中:
{$sort : { score : -1 } }将得分最高的排在分组最后firstN返回分组中后三个得分最低的
js
db.gamescores.aggregate( [
{ $sort : { score : -1 } },
{
$group:
{ _id: "$gameId", playerId:
{
$lastN:
{
input: [ "$playerId","$score" ],
n: 3
}
}
}
}
] )
操作返回下面的结果:
js
[
{
_id: 'G2',
playerId: [ [ 'PlayerC', 66 ], [ 'PlayerB', 14 ], [ 'PlayerA', 10 ] ]
},
{
_id: 'G1',
playerId: [ [ 'PlayerB', 33 ], [ 'PlayerA', 31 ], [ 'PlayerD', 1 ] ]
}
]
根据group的键计算n
可以动态的指定n的值,在下面的例子中$cond表达式被用于gameId字段
js
db.gamescores.aggregate([
{
$group:
{
_id: {"gameId": "$gameId"},
gamescores:
{
$lastN:
{
input: "$score",
n: { $cond: { if: {$eq: ["$gameId","G2"] }, then: 1, else: 3 } }
}
}
}
}
] )
在本例的管道中:
- 使用
$group根据gameId进行分组 - 使用
input : "$score"指定$lastN输入字段 - 如果
gameId是G2则n为1,否则n为3
操作返回下面的结果:
js
[
{ _id: { gameId: "G1" }, gamescores: [ 33, 99, 1 ] },
{ _id: { gameId: "G2" }, gamescores: [ 80 ] }
]
在聚合表达式中使用$lastN
请看下面的聚合:
js
db.aggregate( [
{
$documents: [
{ array: [10, 20, 30, 40] } ]
},
{ $project: {
lastThreeElements:{
$lastN:
{
input: "$array",
n: 3
}
}
}
}
] )
$documents创建了一个包含一个数组的字面量文档$project用于返回$lastN的输出_id被输出省略_id:0$lastN使用输入数组[10, 20, 30, 40]- 返回输入文档数组的后三个元素
操作返回下面的结果:
js
[ { lastThreeElements: [ 20, 30, 40 ] } ]