聚合组和嵌套值的总和
Aggregation with group and sum of nested values
我正在使用 Mongo,我需要聚合以下时间序列,按 account_id
分组并获取每个嵌套值的总和。为了举例,我只使用 pub
对象保持数据集简单,但在我的真实集合中,我还有其他对象和值要聚合
[
{
"account_id": 1,
"pub": {
"cpm": NumberDecimal("1"),
"monthly": NumberDecimal("1.5")
},
"time": ISODate("2022-01-01T01:00:00.000"),
},
{
"account_id": 2,
"pub": {
"cpm": NumberDecimal("3"),
"monthly": NumberDecimal("3.5")
},
"time": ISODate("2022-01-01T01:00:00.000"),
},
{
"account_id": 1,
"pub": {
"cpm": NumberDecimal("2"),
"monthly": NumberDecimal("2.5")
},
"time": ISODate("2022-01-01T02:00:00.000"),
},
{
"account_id": 2,
"pub": {
"cpm": NumberDecimal("4"),
"monthly": NumberDecimal("4.5")
},
"time": ISODate("2022-01-01T02:00:00.000"),
}
]
预期输出
[
{
"_id": 1, // account_id
"pub": {
"cpm": 3,
"monthly": 4
}
},
{
"_id": 2, // account_id
"pub": {
"cpm": 7,
"monthly": 8
}
}
]
我发现以下两种方法可以按预期工作,但对我来说它们似乎非常冗长,尤其是第一种。 考虑到真实集合中还有很多其他对象和值。
方法一
db.collection.aggregate([
{
$group: {
_id: '$account_id',
pub: {
$accumulator: {
init: function () {
return {
cpm: 0,
monthly: 0,
};
},
accumulate: function (state, cpm, monthly) {
return {
cpm: state.cpm + cpm,
monthly: state.monthly + monthly,
};
},
accumulateArgs: [
{ $toDouble: '$pub.cpm' },
{ $toDouble: '$pub.monthly' },
],
merge: function (state1, state2) {
return {
cpm: state1.cpm + state2.cpm,
monthly: state1.monthly + state2.monthly,
};
},
finalize: function (state) {
return {
cpm: state.cpm,
monthly: state.monthly,
};
},
lang: 'js',
},
},
},
}
])
方法二
db.collection.aggregate([
{
"$group": {
"_id": "$account_id",
"pub__cpm": {
$sum: "$pub.cpm"
},
"pub__monthly": {
$sum: "$pub.monthly"
}
}
},
{
$set: {
pub: {
cpm: {
"$toDouble": "$pub__cpm"
},
monthly: {
"$toDouble": "$pub__monthly"
}
},
},
},
{
$unset: [
"pub__cpm",
"pub__monthly"
]
}
)]
这样的东西会很棒
{
"$group": {
"_id": "$account_id",
pub: {
cpm: { $sum: "$pub.cpm" },
monthly: { $sum: "$pub.monthly" },
},
}
}
但它抛出“字段“$pub”必须是一个累加器对象”,这就是我最终使用第一种方法的原因。
有更好的方法可以达到同样的效果吗?如果不是,哪种方法更快?
谢谢
您可以使用 $project 来格式化您的输出,而不是 $set
和 $unset
使用 $project
像这样
db.collection.aggregate([
{
"$group": {
"_id": "$account_id",
"pub__cpm": { $sum: "$pub.cpm" },
"pub__monthly": { $sum: "$pub.monthly" }
}
},
{
"$project": {
"pub": {
"cpm": "$pub__cpm",
"monthly": "$pub__monthly"
}
}
}
])
小组赛结束后,您可以使用 project
操作将变量 cpm 和月度的累计总和投影到 pub
中。
db.collection.aggregate([
{
"$group": {
"_id": "$account_id",
cpm: {
$sum: "$pub.cpm"
},
monthly: {
$sum: "$pub.monthly"
},
}
},
{
"$project": {
pub: {
cpm: "$cpm",
monthly: "$monthly"
}
}
}
])
我正在使用 Mongo,我需要聚合以下时间序列,按 account_id
分组并获取每个嵌套值的总和。为了举例,我只使用 pub
对象保持数据集简单,但在我的真实集合中,我还有其他对象和值要聚合
[
{
"account_id": 1,
"pub": {
"cpm": NumberDecimal("1"),
"monthly": NumberDecimal("1.5")
},
"time": ISODate("2022-01-01T01:00:00.000"),
},
{
"account_id": 2,
"pub": {
"cpm": NumberDecimal("3"),
"monthly": NumberDecimal("3.5")
},
"time": ISODate("2022-01-01T01:00:00.000"),
},
{
"account_id": 1,
"pub": {
"cpm": NumberDecimal("2"),
"monthly": NumberDecimal("2.5")
},
"time": ISODate("2022-01-01T02:00:00.000"),
},
{
"account_id": 2,
"pub": {
"cpm": NumberDecimal("4"),
"monthly": NumberDecimal("4.5")
},
"time": ISODate("2022-01-01T02:00:00.000"),
}
]
预期输出
[
{
"_id": 1, // account_id
"pub": {
"cpm": 3,
"monthly": 4
}
},
{
"_id": 2, // account_id
"pub": {
"cpm": 7,
"monthly": 8
}
}
]
我发现以下两种方法可以按预期工作,但对我来说它们似乎非常冗长,尤其是第一种。 考虑到真实集合中还有很多其他对象和值。
方法一
db.collection.aggregate([
{
$group: {
_id: '$account_id',
pub: {
$accumulator: {
init: function () {
return {
cpm: 0,
monthly: 0,
};
},
accumulate: function (state, cpm, monthly) {
return {
cpm: state.cpm + cpm,
monthly: state.monthly + monthly,
};
},
accumulateArgs: [
{ $toDouble: '$pub.cpm' },
{ $toDouble: '$pub.monthly' },
],
merge: function (state1, state2) {
return {
cpm: state1.cpm + state2.cpm,
monthly: state1.monthly + state2.monthly,
};
},
finalize: function (state) {
return {
cpm: state.cpm,
monthly: state.monthly,
};
},
lang: 'js',
},
},
},
}
])
方法二
db.collection.aggregate([
{
"$group": {
"_id": "$account_id",
"pub__cpm": {
$sum: "$pub.cpm"
},
"pub__monthly": {
$sum: "$pub.monthly"
}
}
},
{
$set: {
pub: {
cpm: {
"$toDouble": "$pub__cpm"
},
monthly: {
"$toDouble": "$pub__monthly"
}
},
},
},
{
$unset: [
"pub__cpm",
"pub__monthly"
]
}
)]
这样的东西会很棒
{
"$group": {
"_id": "$account_id",
pub: {
cpm: { $sum: "$pub.cpm" },
monthly: { $sum: "$pub.monthly" },
},
}
}
但它抛出“字段“$pub”必须是一个累加器对象”,这就是我最终使用第一种方法的原因。
有更好的方法可以达到同样的效果吗?如果不是,哪种方法更快? 谢谢
您可以使用 $project 来格式化您的输出,而不是 $set
和 $unset
使用 $project
像这样
db.collection.aggregate([
{
"$group": {
"_id": "$account_id",
"pub__cpm": { $sum: "$pub.cpm" },
"pub__monthly": { $sum: "$pub.monthly" }
}
},
{
"$project": {
"pub": {
"cpm": "$pub__cpm",
"monthly": "$pub__monthly"
}
}
}
])
小组赛结束后,您可以使用 project
操作将变量 cpm 和月度的累计总和投影到 pub
中。
db.collection.aggregate([
{
"$group": {
"_id": "$account_id",
cpm: {
$sum: "$pub.cpm"
},
monthly: {
$sum: "$pub.monthly"
},
}
},
{
"$project": {
pub: {
cpm: "$cpm",
monthly: "$monthly"
}
}
}
])