具有数组值总和的MongoDB聚合

bud*_*123 7 mongodb mongodb-query aggregation-framework

我有一个包含以下数据的集合:

{
    "_id" : ObjectId("5516d416d0c2323619ddbca8"),
    "date" : "28/02/2015",
    "driver" : "user1",
    "passengers" : [
        {
            "user" : "user2",
            "times" : 2
        },
        {
            "user" : "user3",
            "times" : 3
        }
    ]
}
{
    "_id" : ObjectId("5516d517d0c2323619ddbca9"),
    "date" : "27/02/2015",
    "driver" : "user2",
    "passengers" : [
        {
            "user" : "user1",
            "times" : 2
        },
        {
            "user" : "user3",
            "times" : 2
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

并且我想执行聚合以便我知道某个乘客,与某个驱动程序相关的时间,在我的示例中它将是:对于user1:[{ driver: user2, times: 2}] 对于user2:[{ driver: user1, times: 2}] 对于user3:[{ driver: user1, times: 3}, {driver: user2, times:2}]

我对mongo很新,并且知道如何使用sum执行简单的聚合,但不是当它的内部数组,以及当我的主题本身在数组中时.什么是执行这种聚合的适当方式,更具体地说,我如何在基于express.js的服务器中执行它?

chr*_*dam 15

为了通过聚合框架实现您的需求,第一个管道阶段将是有$match问题的乘客的操作,该操作将文档与乘客阵列中的用户匹配,然后是$unwind在先前操作中从输入文档解构乘客阵列的操作.输出每个元素的文档.$match解构数组上的另一个操作是进一步过滤先前的文档流,以允许仅匹配的文档未经修改地传递到下一个管道阶段,该阶段是与$project操作员一起投射所需的字段.所以基本上你的聚合管道user3就像:

db.collection.aggregate([
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$unwind": "$passengers"
     },
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$project": {
             "_id": 0,
            "driver": "$driver",
            "times": "$passengers.times"
        }
     }
])
Run Code Online (Sandbox Code Playgroud)

结果:

/* 0 */
{
    "result" : [ 
        {
            "driver" : "user1",
            "times" : 3
        }, 
        {
            "driver" : "user2",
            "times" : 2
        }
    ],
    "ok" : 1
}
Run Code Online (Sandbox Code Playgroud)

更新:

对于在具有不同日期的驾驶员上对重复项进行分组,正如您所提到的,您可以$group在最后一个$project管道阶段之前进行操作,您可以使用$sum运算符计算总乘客时间:

db.collection.aggregate([
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$unwind": "$passengers"
     },
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$group": {
             "_id": "$driver", 
             "total": {
                 "$sum": "$passengers.times"
             }
         }
     },
     {
         "$project": {
            "_id": 0,
            "driver": "$_id",
            "total": 1
        }
     }
])
Run Code Online (Sandbox Code Playgroud)

结果:

/* 0 */
{
    "result" : [ 
        {
            "total" : 2,
            "driver" : "user2"
        }, 
        {
            "total" : 3,
            "driver" : "user1"
        }
    ],
    "ok" : 1
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这非常接近我的需求(它没有从不同日期分组重复的驱动程序).我最终使用了`$ group:{"_ id":"$ driver","total":{$ sum:"$ passengers.times"}}`, (2认同)