MongoDb在同一记录

时间:2015-10-19 20:56:08

标签: mongodb mongodb-query aggregation-framework

我有一个收藏品。我试图得到记录中字段的总和/计数。我还需要记录中嵌套数组字段的总和/计数。  我正在使用MongoDB 3.0.0和Jongo。

请在下面找到我的记录:

  

db.events.insert([{

"eventId": "a21sda2s-711f-12e6-8bcf-p1ff819aer3o",
"orgName": "ORG1",
"eventName": "EVA2",
"eventCost": 5000,
"bids": [{
        "vendorName": "v1",
        "bidStatus": "ACCEPTED",
        "bidAmount": 4400
    },{
        "vendorName": "v2",
        "bidStatus": "PROCESSING",
        "bidAmount": 4900
    },{
        "vendorName": "v3",
        "bidStatus": "REJECTED",
        "bidAmount": "3000"
    }] }, {
"eventId": "4427f318-7699-11e5-8bcf-feff819cdc9f",
"orgName": "ORG1",
"eventName": "EVA3",
"eventCost": 1000,
"bids": [ {
        "vendorName": "v1",
        "bidStatus": "REJECTED",
        "bidAmount": 800
    }, {
        "vendorName": "v2",
        "bidStatus": "PROCESSING",
        "bidAmount": 900
    },{
        "vendorName": "v3",
        "bidStatus": "PROCESSING",
        "bidAmount": 990
    }] }])

我需要$ eventCount和$ eventCost汇总$ eventCost字段。 我通过汇总$ bids.bidAmount字段获得$ acceptedCount和$ acceptedAmount(条件为$ bid.bidStatus)

我需要的结果是:

[
{
"_id" : "EVA2",
"eventCount" : 2,
"eventCost" : 10000,
"acceptedCount" : 2,
"acceptedAmount" : 7400 },
{ 
"_id" : "EVA3",
"eventCount" : 1,
"eventCost" : 1000 ,
 "acceptedCount" : 0,
"acceptedAmount" : 0 },
}]

我无法在单个查询中获得结果。现在我创建两个查询A和查询B(参见下文)并将它们合并到我的Java代码中。 我在查询B中使用$ unwind运算符。

我是否有办法在单个查询中实现相同的结果。我觉得我需要的是一种方法来将bid []数组传递给下游管道中的下一个操作。

我尝试过$ push运算符,但我无法想象,这是一种将整个bid []数组推向下游的方法。

我不想改变我的记录结构,但如果有一些内在错误,我可以尝试一下。谢谢你的帮助。

我的解决方案

查询A:

db.events.aggregate([
    {$group: {
        _id: "$eventName",
        eventCount:     {$sum: 1}, // Get count of all events
        eventCost: {$sum: "$eventCost"} // Get sum of costs
    } }
])

查询B:

db.events.aggregate([
    {$unwind: "$bids" },
    {$group: {
        _id: "$eventName",
        // Get Count of Bids that have been accepted
        acceptedCount:{ $sum:{$cond: [{$eq: ["$bids.bidStatus","ACCEPTED"]} ,1,0] } } ,
        // Get Sum of Amounts that have been accepted
        acceptedAmount:{$sum:{$cond: [{$eq: ["$bids.bidStatus","ACCEPTED"]} ,"$bids.bidAmount",0]

    } } } }  
])

在Java代码中加入Query A和QueryB。

我需要什么:

完成相同的单个数据库操作

1 个答案:

答案 0 :(得分:1)

展开数组的问题是,如果您在进行初始分组之前尝试解开这些数据,它会破坏您的分组事件的计数,因为每个文档数组中的项目数将影响计数和与未经过格式化的文件的总和。

如果您的数据大小合适,那么使用$push简单地创建和"数组" "数组",当然你只需在每个分组文档上处理$unwind两次:

db.events.aggregate([
    { "$group": {
        "_id": "$eventName",
        "eventCount": { "$sum": 1 },
        "eventCost": { "$sum": "$eventCost" },
        "bids": { "$push": "$bids" }
    }},
    { "$unwind": "$bids" },
    { "$unwind": "$bids" },
    { "$group": {
        "_id": "$_id",
        "eventCount": { "$first": "$eventCount" },
        "eventCost": { "$first": "$eventCost" },
        "acceptedCount":{
            "$sum":{
                "$cond": [
                    { "$eq": [ "$bids.bidStatus","ACCEPTED" ] },
                    1,
                    0
                ]
            }
        },
        "acceptedCost":{
            "$sum":{
                "$cond": [
                    { "$eq": [ "$bids.bidStatus","ACCEPTED" ] },
                    "$bids.bidAmount",
                    0
                ]
            }
        }
    }}
])

可能更好的替代方案是总结"接受"首先是每个文档中的值,然后按照"事件"后:

db.events.aggregate([
    { "$unwind": "$bids" },
    { "$group": {
        "_id": "$_id",
        "eventName": { "$first": "$eventName" },
        "eventCost": { "$first": "$eventCost" },
        "acceptedCount":{
            "$sum":{
                "$cond": [
                    { "$eq": [ "$bids.bidStatus","ACCEPTED" ] },
                    1,
                    0
                ]
            }
        },
        "acceptedCost":{
            "$sum":{
                "$cond": [
                    { "$eq": [ "$bids.bidStatus","ACCEPTED" ] },
                    "$bids.bidAmount",
                    0
                ]
            }
        }
    }},
    { "$group": {
        "_id": "$eventName",
        "eventCount": { "$sum": 1 },
        "eventCost": { "$sum": "$eventCost" },
        "acceptedCount": { "$sum": "$acceptedCount" },
        "acceptedCost": { "$sum": "$acceptedCost" }
    }}
])

通过这种方式,每个数组都减少到你需要收集的值,这使得后者$group变得更容易。

这些是两种方法,后者是更好的选择,但是如果您实际上能够并行处理两个查询并以智能方式组合它们,那么就像我目前所做的那样运行两个查询将是我的建议达到最佳表现的方法。