MongoDB 数组值之和的聚合

MongoDB Aggregation with sum of array values

我有一个 collection 包含以下数据:

{
    "_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
        }
    ]
}

而且我想执行聚合,以便我知道某个乘客与某个 driver 的时间,在我的示例中它将是: 对于用户 1:[{ driver: user2, times: 2}] 对于用户 2:[{ driver: user1, times: 2}] 对于用户 3:[{ driver: user1, times: 3}, {driver: user2, times:2}]

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

为了使用聚合框架满足您的需求,第一个管道阶段将是一个 $match operation on the passenger in question that matches the documents with the user in the passenger array, followed by the $unwind operation which deconstructs the passengers array from the input documents in the previous operation to output a document for each element. Another $match operation on the deconstructed array follows that further filters the previous document stream to allow only matching documents to pass unmodified into the next pipeline stage, which is projecting the required fields with the $project 运算符。所以基本上你的 user3 的聚合管道将是这样的:

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

结果:

/* 0 */
{
    "result" : [ 
        {
            "driver" : "user1",
            "times" : 3
        }, 
        {
            "driver" : "user2",
            "times" : 2
        }
    ],
    "ok" : 1
}

更新:

如您所提到的,为了对具有不同日期的驱动程序的重复项进行分组,您可以在最后一个 $project 管道阶段之前执行 $group 操作使用 $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
        }
     }
])

结果:

/* 0 */
{
    "result" : [ 
        {
            "total" : 2,
            "driver" : "user2"
        }, 
        {
            "total" : 3,
            "driver" : "user1"
        }
    ],
    "ok" : 1
}