需要在MongoDB中对数组对象的值进行求和

5

我正在尝试计算总值,如果该值存在的话。但是查询并没有完全成功。所以有人能帮助我解决这个问题吗?这是我的样本文件。我已经附上了两个文档,请查看这些文档并找出最佳解决方案。 文档:1

{
    "_id" : 1"),
    "message_count" : 4,
    "messages" : {
        "data" : [ 
            {
                "id" : "11",
                "saleValue": 1000
            }, 
            {
                "id" : "112",
                "saleValue": 1400
            }, 
            {
                "id" : "22",

            }, 
            {
                "id" : "234",
                "saleValue": 111
            }
        ],

    },
    "createdTime" : ISODate("2018-03-18T10:18:48.000Z")
}

文档:2

 {
        "_id" : 444,
        "message_count" : 4,
        "messages" : {
            "data" : [ 
                {
                    "id" : "444",
                    "saleValue" : 2060
                }, 
                {
                    "id" : "444",
                }, 
                {
                    "id" : 234,
                    "saleValue" : 260
                }, 
                {
                    "id" : "34534",
                }
            ]
        },

        "createdTime" : ISODate("2018-03-18T03:11:50.000Z")
    }

需要的输出:

{
   total : 4831
}

我的查询:

db.getCollection('myCollection').aggregate([
    {
        "$group": {
            "_id": "$Id",

            "totalValue": {
                $sum: {
                    $sum: "$messages.data.saleValue"
                }
            }

        }
    }
])

如果可能的话,请帮忙解决这个问题。非常感谢。


1
使用unwind函数对 data 数组展开,并累加 data.value - Clement Amarnath
5个回答

8

它没有正确运行,因为它正在聚合集合中的所有文档;您正在对一个常量"_id": "tempId"进行分组,您只需要通过添加$引用正确的键:

db.getCollection('myCollection').aggregate([
    { "$group": {
        "_id": "$tempId",
        "totalValue": { 
            "$sum": { "$sum": "$messages.data.saleValue" } 
        }
    } }
])

本质上,这是聚合操作的单阶段管道版本,其中有一个额外的字段来保存组管道之前的求和表达式,并将该字段作为组中的$sum运算符调用。

以上工作是因为MongoDB 3.2+中的$sum$project$group阶段都可用,当在$project阶段中使用时,$sum返回表达式列表的总和。 表达式"$messages.data.value"返回数字列表[120, 1200],然后将其用作$sum表达式:

db.getCollection('myCollection').aggregate([
    { "$project": {
        "values": { "$sum": "$messages.data.value" },
        "tempId": 1,
    } },
    { "$group": {
        "_id": "$tempId",
        "totalValue": { "$sum": "$values" }
    } }
])

我已经更新了我的问题。请检查并帮助我找出答案。 - Nazmul
失败的原因是 "saleValue" 是一个字符串,而不是一个数字。$sum 无法正确处理字符串类型的值,请在运行pipeline之前将字段转换为数值类型。 - chridam
能否对 saleValue 字符串进行求和?我能将该值转换为可求和的类型吗? - Nazmul
@NazmulHossain 如上面的评论中提到的,它不能处理字符串值。而且你不能在聚合操作期间将其转换为数值类型。在运行聚合管道之前,您需要先更改模式以获得正确的结果,或者如果情况不同,则使用mapReduce。 - chridam
我遇到了问题。因为我的生产数据库已经包含了 saleValue 字符串,而不是整数。所以我正在拼命地寻找解决方案,我该怎么办 :( - Nazmul
显示剩余4条评论

1
你可以在 $group 前添加 $unwind,这样你就可以将数据数组解构,然后正确地进行分组:
db.myCollection.aggregate([
{
    "$unwind": "$messages.data"
},
{
    "$group": {
        "_id": "tempId",
        "totalValue": {
            $sum: {
                $sum: "$messages.data.value"
            }
        }
    }
}
])

输出:

{ "_id" : "tempId", "totalValue" : 1320 }

1
db.getCollection('myCollection').aggregate([
   {
     $unwind: "$messages.data",
     $group: {
        "_id": "tempId",
        "totalValue": { $sum: "$messages.data.value" }
     }
   }
])

$unwind

,这段代码与编程有关。

1
根据上述问题描述,作为解决方案,请尝试执行以下聚合查询。
db.myCollection.aggregate(

    // Pipeline
    [
        // Stage 1
        {
            $unwind: {
                path: '$messages.data'
            }
        },

        // Stage 2
        {
            $group: {
                _id: {
                    pageId: '$pageId'
                },
                total: {
                    $sum: '$messages.data.saleValue'
                }
            }
        },

        // Stage 3
        {
            $project: {
                pageId: '$_id.pageId',
                total: 1,
                _id: 0
            }
        }

    ]


);

1

您可以不使用$group。分组会使其他数据变得更加复杂,难以管理和处理。因此,我更喜欢使用下面所示的$sum$map

db.getCollection('myCollection').aggregate([
 {
   $addFields: {
      total: {
          $sum: {
            $map: {
              input: "$messages.data",
              as: "message",
              in: "$$message.saleValue",
            },
          },
        },
      },
    }, 
  } 
])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接