文章目录
- MongoDB聚合运算符:$lastN
- 语法
- 使用
- 空值或缺失值的处理
- l a s t N 与 lastN与 lastN与bottomN对比
- 关于窗口功能和聚合表达式的支持
- 内存限制
- 举例
- 查找单场比赛的后三名运动员得分
- 查找多场比赛中后三名运动员的得分
- s o r t 与 sort与 sort与lastN一起使用
- 根据group的键计算n
- 在聚合表达式中使用$lastN
MongoDB聚合运算符:$lastN
$lastN
聚合运算符返回分组中后n个元素的聚合,只有在分组元素是有序的情况下才有意义,如果分组中的元素个数小于n,将返回分组中所有的元素。
语法
{
$lastN:
{
input: <expression>,
n: <expression>
}
}
-
input
指定要从文档中获取的字段或表达式值,可以是任何表达式 -
n
n 必须是正整数表达式,可以是常量,也可以是$group
的_id
值。
使用
空值或缺失值的处理
-
$lastN
不会过滤掉空值 - 缺失的值会被
$lastN
转换为null
下面的聚合返回每个分组的最后5个文档:
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
:G1
-
PlayerD
的得分得分不存在,PlayerE
的得分为null,这两者的值都为都会被认为是null
-
input: "$score"
指定给firstFiveScores
字段并返回一个数组 - 由于没有排序标准,因此返回后5个分数字段
[
{
_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
集合:
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
单场比赛的前三名得分:
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
游戏后三个文档
操作返回的结果如下:
[
{
_id: "G1",
lastThreeScores: [ [ "PlayerB", 33 ], [ "PlayerC", 99 ], [ "PlayerD", 1 ] ]
}
]
查找多场比赛中后三名运动员的得分
使用$lastN
查找每个比赛中前n
个输入字段:
db.gamescores.aggregate( [
{
$group:
{
_id: "$gameId", playerId:
{
$lastN:
{
input: [ "$playerId","$score" ],
n: 3
}
}
}
}
] )
在本例聚合管道中:
- 使用
$group
根据gameId
进行分组 - 使用
$lastN
和n:3
返回比赛前三个文档 - 为
$lastN
指定输入字段input : ["$playerId", "$score"]
操作返回下面的结果:
[
{
_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
db.gamescores.aggregate( [
{ $sort : { score : -1 } },
{
$group:
{ _id: "$gameId", playerId:
{
$lastN:
{
input: [ "$playerId","$score" ],
n: 3
}
}
}
}
] )
在这个例子中:
-
{$sort : { score : -1 } }
将得分最高的排在分组最后 -
firstN
返回分组中后三个得分最低的
db.gamescores.aggregate( [
{ $sort : { score : -1 } },
{
$group:
{ _id: "$gameId", playerId:
{
$lastN:
{
input: [ "$playerId","$score" ],
n: 3
}
}
}
}
] )
操作返回下面的结果:
[
{
_id: 'G2',
playerId: [ [ 'PlayerC', 66 ], [ 'PlayerB', 14 ], [ 'PlayerA', 10 ] ]
},
{
_id: 'G1',
playerId: [ [ 'PlayerB', 33 ], [ 'PlayerA', 31 ], [ 'PlayerD', 1 ] ]
}
]
根据group的键计算n
可以动态的指定n
的值,在下面的例子中$cond
表达式被用于gameId
字段
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
操作返回下面的结果:
[
{ _id: { gameId: "G1" }, gamescores: [ 33, 99, 1 ] },
{ _id: { gameId: "G2" }, gamescores: [ 80 ] }
]
在聚合表达式中使用$lastN
请看下面的聚合:
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]
- 返回输入文档数组的后三个元素
操作返回下面的结果:
[ { lastThreeElements: [ 20, 30, 40 ] } ]