如何对 doctrine odm 中的多个字段求和?

How do I sum multiple fields in doctrine odm?

我想使用 doctrine odm 的聚合生成器来构建此查询:

db.TeamStandings.aggregate(

    // Pipeline
    [
        // Stage 1
        {
            $match: {
                "team.$id": ObjectId("5a1643fdf5d8741a883c2aeb")
            }
        },

        // Stage 2
        {
            $group: {
                "_id": { "team": "team.$id" },

                // This is the sum of multiple fields
                "games": { $sum: { $sum: ["$wins", "$losses", "$ties"] } }, 

                "wins": { $sum: "$wins" },
                "losses": { $sum: "$losses" },
                "ties": { $sum: "$ties" },
                "homeWins" : { $sum: "$homeRecord.wins" },
                "homeLosses" : { $sum: "$homeRecord.losses" },
                "homeTies" : { $sum: "$homeRecord.ties" },
                "roadWins" : { $sum: "$roadRecord.wins" },
                "roadLosses" : { $sum: "$roadRecord.losses" },
                "roadTies" : { $sum: "$roadRecord.ties" },
            }
        },

    ]
);

我在 Studio3T 中执行了这个并得到了以下信息:

{ 
    "_id" : {
        "team" : "team.$id"
    }, 
    "games" : NumberInt(776), 
    "wins" : NumberInt(377), 
    "losses" : NumberInt(398), 
    "ties" : NumberInt(1), 
    "homeWins" : NumberInt(218), 
    "homeLosses" : NumberInt(170), 
    "homeTies" : NumberInt(1), 
    "roadWins" : NumberInt(159), 
    "roadLosses" : NumberInt(228), 
    "roadTies" : NumberInt(0)
}

如何使用 doctrine odm 的聚合生成器编写这个确切的查询?

这个比较棘手,因为文档不是很清楚。

理论上,您可以创建一个嵌套的子表达式并在其中使用求和运算符:

$builder = $this->dm->createAggregationBuilder(\Documents\BlogPost::class);
$builder->group()
    ->field('id')
    ->expression(null)
    ->field('games')
    ->sum($builder->expr()->sum('$wins', '$losses', '$ties'))
;

但是,由于聚合构建器的构建方式,它不太理解 $project 阶段之外的多个表达式的总和 syntax,导致以下(错误)结果:

[{
    "$group": {
        "_id": null,
        "games": { "$sum": { "$sum": "$wins" } }
    }
}]

要解决此问题,请在嵌套表达式中使用 $add 运算符而不是 $sum

$builder = $this->dm->createAggregationBuilder(\Documents\BlogPost::class);
$builder->group()
    ->field('id')
    ->expression(null)
    ->field('games')
    ->sum($builder->expr()->add('$wins', '$losses', '$ties'))
;

这会创建您希望它创建的聚合管道。

之所以奇怪,是因为文档定义了 $sum$group$project 阶段使用时的不同行为:在 $group 中,它接受单个参数,而在 $project 中它接受多个参数。但是,它在 $group 中的嵌套表达式中的行为并不完全清楚:您发布的聚合管道有效的事实表明它没有将子表达式视为在 $group 中阶段,从而允许多个参数。当我构建运算符时,我假设相反:只有在 $project 阶段才应该 $sum 接受多个参数,否则默认为一个参数语法。

我会在 MongoDB ODM 中为此创建一个工单,然后看看是否可以轻松解决这个问题。