我正在编写一条聚合管道以返回赢率。当我使用$ sum时,值是从 $ facet $ project 在数组中输出的。这让我感到困惑。为了解决这个问题,我在计算winRatio时只需在数组上运行$ sum,效果很好。 如何使用$ project而不将值添加到数组中?
Round.aggregate([
{
$match: {
$and: query,
},
},
{
$facet: {
wins: [
{
$match: {
winner: user,
},
},
{
$group: {
_id: { user: '$scores.player', game: '$game' },
value: { $sum: 1 }, // value *not* within array
},
},
],
rounds: [
{
$unwind: '$scores',
},
{
$match: {
'scores.player': user,
},
},
{
$group: {
_id: { user: '$scores.player', game: '$game' },
value: { $sum: 1 }, // value *not* within array
},
},
],
},
},
{
$project: {
_id: '$rounds._id',
rounds: '$rounds.value', // value within an array
wins: '$wins.value', // value within an array
winRatio: { ... },
},
},
]);
模式:
const schema = new mongoose.Schema(
{
game: { type: mongoose.Schema.ObjectId, required: true },
scores: [
{
player: { type: mongoose.Schema.ObjectId, ref: 'User', required: true },
playerName: { type: String }, // denormalise
score: { type: Number, required: true },
},
],
winner: { type: mongoose.Schema.ObjectId, required: true },
datePlayed: { type: Date },
},
{ timestamps: true },
);
答案 0 :(得分:0)
您问为什么$sum
'有效'和$project
剂量。
让我们首先了解$ facet阶段的输出。
{
"wins" : [
{
"_id" : {
"user" : [
"player1",
"player2"
],
"game" : 1.0
},
"value" : 2.0
}
],
"rounds" : [
{
"_id" : {
"user" : "player1",
"game" : 1.0
},
"value" : 3.0
}
]
}
我们可以看到每个文档结果都是一个数组,即使您在最后将其分组,也可以将每个结果想象成它自己的聚合,返回值始终是一个数组(为空或不取决于结果)。
因此,当您在$project
上$rounds.value
时,您是在告诉mongo在数组中保留每个结果的value字段。在我们的情况下,只有一个,但仍然如此。
另一方面,
$sum
是来自文档的累积运算符:
使用单个表达式作为其操作数,如果表达式解析为数组,则$ sum遍历数组以对数组的数字元素进行操作以返回单个值。
快速解决您的“问题”只是在投影时添加$sum
:
{
$project: {
_id: '$rounds._id',
rounds: {$sum: '$rounds.value'},
wins: {$sum: '$wins.value'},
winRatio: { ... },
},
},