【问题标题】:Mongo DB AggregateMongoDB聚合
【发布时间】:2017-10-24 22:49:15
【问题描述】:

我有一个包含如下条目的集合:

{"placeId" : "0b980482-ab4b-4685-95ab-ecc2dcba1837","placeName" : "B8 Göteborg","created" : ISODate("2017-04-09T14:53:01.005Z"),"debitAccount" : "1581","debitAmount" : 26.0,"creditAccount" : "3013","creditAmount" : 23.2142791748047,"taxAccount" : "2620","taxAmount" : 2.78572010993958},
{"placeId" : "0b980482-ab4b-4685-95ab-ecc2dcba1837","placeName" : "B8 Göteborg","created" : ISODate("2017-04-09T14:53:01.005Z"),"debitAccount" : "1581","debitAmount" : 26.0,"creditAccount" : "3014","creditAmount" : 53.2142791748047,"taxAccount" : "2621","taxAmount" : 5.78572010993958}

我希望输出类似于:

{
    "_id" : "B8 - Göteborg",
    "days" : [ 
        {
            "date" : "2017-03-24",
            "creditAccounts" : [ 
                {
                    "creditAccount" : "3013",
                    "creditAccountSum" : 23.214279174804
                }, 
                {
                    "creditAccount" : "3014",
                    "creditAccountSum" : 53.2142791748047,
                }, 
            ],
            "debitAccounts" : [ 
                {
                    "debitAccount" : "1581",
                    "debitAccountSum" : 52
                }
            ],
            "taxAccounts" : [ 
                {
                    "taxAccount" : "2620",
                    "taxAccountSum" : 2.78572010993958
                },
                {
                    "taxAccount" : "2621",
                    "taxAccountSum" : 5.78572010993958
                }
            ]
        }
    ]
}

即每个 placeName 和 day 都有一个所有唯一 creditAccounts、debitAccounts、taxAccounts 及其总和的列表。我已经设法对其中一个字段进行分组,它看起来像:

db.getCollection('accounting_records').aggregate([
    {$match : {...},  
    {$group: {_id: {placeName :'$placeName',year: {$substr: ['$created',0,4]},month: {$substr: ['$created',5,2]},dayOfMonth: {$substr: ['$created',8,2]},creditAccount:'$creditAccount'}, created: {$max: '$created'},records: { $addToSet: "$$ROOT" }}},
    {$sort : {created : 1}},
    {$group: {_id: {placeName :'$_id.placeName',year: '$_id.year',month: '$_id.month',dayOfMonth: '$_id.dayOfMonth'},created: {$max: '$created'}, creditAccounts:{$push :{creditAccount: '$_id.creditAccount',sum : {$sum: '$records.creditAmount'}, creditAccountName:'$records.creditAccountName'}}}},
    {$sort : {created : 1}},
    {$group : {_id : '$_id.placeName', created: {$max: '$created'}, days : {$push: {date: {$concat: ['$_id.year','-','$_id.month','-','$_id.dayOfMonth']},creditAccounts : '$creditAccounts'}}}},
    {$sort : {_id : 1}},
])

但我不知道如何对所有 3 个 creditAccount、taxAccount 和 debitAccount 进行分组。也许使用 mapReduce 是可能的,但没有考虑到这一点,因为我发现与使用聚合框架相比,读取性能要差得多。

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:
    You need to `$group` each credit/debit/tax-Account/Amount and calculate sum.
    
    
    
    db.collection.aggregate([
        {
            $group: {
                _id:{_id:"$placeName",date:{$dateToString:{format:"%Y-%m-%d" , date:"$created"}}, creditAccount:"$creditAccount" },
                creditAccountSum : {$sum: "$creditAmount"},
                remaining: {$push: {debitAccount:"$debitAccount",debitAmount:"$debitAmount",taxAccount:"$taxAccount",taxAmount:"$taxAmount"}}
            }
        },
        {$unwind: "$remaining"},
        {
            $group: {
                _id:{_id:"$_id._id",date:"$_id.date", debitAccount:"$remaining.debitAccount"},
                debitAccountSum : {$sum: "$remaining.debitAmount"},
                remaining: {$push: {creditAccount:"$_id.creditAccount",creditAccountSum:"$creditAccountSum", taxAccount:"$remaining.taxAccount",taxAmount:"$remaining.taxAmount"}}
            }
        },
        {$unwind: "$remaining"},
        {
            $group: {
                _id:{_id:"$_id._id",date:"$_id.date", taxAccount:"$remaining.taxAccount"},
                taxAccountSum : {$sum: "$remaining.taxAmount"},
                remaining: {$push :{creditAccount:"$remaining.creditAccount",creditAccountSum:"$remaining.creditAccountSum", debitAccount:"$_id.debitAccount", debitAccountSum:"$debitAccountSum"}}
            }
        },
        {$unwind: "$remaining"},
        {   
            $group : {
                    _id:{_id:"$_id._id",date:"$_id.date"},
                    creditAccounts:{$addToSet:{creditAccount:"$remaining.creditAccount",creditAccountSum:"$remaining.creditAccountSum"}},
                    debitAccounts:{$addToSet:{debitAccount:"$remaining.debitAccount",debitAccountSum:"$remaining.debitAccountSum"}},
                    taxAccounts:{$addToSet:{taxAccount:"$_id.taxAccount",taxAccountSum:"$taxAccountSum"}}      
            }
        },
        {
            $group : {
                _id : {_id:"$_id._id"},
                days : {$push: {date:"$_id.date",creditAccounts:"$creditAccounts",debitAccounts:"$debitAccounts", taxAccounts:"$taxAccounts"}}
            }
        },
        {
            $project: {
                _id:"$_id._id",
                days:"$days"
            }
        }
    ]).pretty()
    

    测试数据:

    {"placeId" : "0b980482-ab4b-4685-95ab-ecc2dcba1837","placeName" : "B8 Göteborg","created" : ISODate("2017-04-09T14:53:01.005Z"),"debitAccount" : "1581","debitAmount" : 26.0,"creditAccount" : "3013","creditAmount" : 23.2142791748047,"taxAccount" : "2620","taxAmount" : 2.78572010993958},
    {"placeId" : "0b980482-ab4b-4685-95ab-ecc2dcba1837","placeName" : "B8 Göteborg","created" : ISODate("2017-04-09T14:53:01.005Z"),"debitAccount" : "1581","debitAmount" : 26.0,"creditAccount" : "3014","creditAmount" : 53.2142791748047,"taxAccount" : "2621","taxAmount" : 5.78572010993958},
    {"placeId" : "0b980482-ab4b-4685-95ab-ecc2dcba1837","placeName" : "B8 Göteborg","created" : ISODate("2017-05-09T14:53:01.005Z"),"debitAccount" : "1581","debitAmount" : 26.0,"creditAccount" : "3014","creditAmount" : 53.2142791748047,"taxAccount" : "2621","taxAmount" : 5.78572010993958}
    

    输出:

    {
        "_id" : "B8 Göteborg",
        "days" : [
            {
                "date" : "2017-04-09",
                "creditAccounts" : [
                    {
                        "creditAccount" : "3014",
                        "creditAccountSum" : 53.2142791748047
                    },
                    {
                        "creditAccount" : "3013",
                        "creditAccountSum" : 23.2142791748047
                    }
                ],
                "debitAccounts" : [
                    {
                        "debitAccount" : "1581",
                        "debitAccountSum" : 52
                    }
                ],
                "taxAccounts" : [
                    {
                        "taxAccount" : "2621",
                        "taxAccountSum" : 5.78572010993958
                    },
                    {
                        "taxAccount" : "2620",
                        "taxAccountSum" : 2.78572010993958
                    }
                ]
            },
            {
                "date" : "2017-05-09",
                "creditAccounts" : [
                    {
                        "creditAccount" : "3014",
                        "creditAccountSum" : 108.4285583496094
                    }
                ],
                "debitAccounts" : [
                    {
                        "debitAccount" : "1581",
                        "debitAccountSum" : 52
                    }
                ],
                "taxAccounts" : [
                    {
                        "taxAccount" : "2621",
                        "taxAccountSum" : 12.57144021987916
                    }
                ]
            }
        ]
    }
    

    【讨论】:

    • 感谢您的回复。但它并没有真正起到作用,因为我希望 creditAccounts/debitAccounts/taxaccounts 中的每个条目都是唯一的。在您发布的回复中“debitAccount”:“1581”出现了两次,所以我想我必须将 thoose 添加到 _id 顶级分组中?比如:_id:{_id:"$placeName",date:{$dateToString:{format:"%Y-%m-%d", date:"$created"}}, creditAccount: '$creditAccount',debitAccount: '$debitAccount',taxAccount : '$taxAccount'},
    • @FrejHåkansson 如果您想要列表中的唯一项目,请使用 $addToSet 而不是 $push,因为我已经更新了答案。
    • 也许我有点不清楚。 taxAccount/creditAccount/debitAccount 字段是 id,并且列表:creditAccounts/debitAccounts/taxAccounts 应该包含每个 taxAccount/creditAccount/debitAccount 的 taxAmount/debitAmount/creditAmount 的总和。因此,在我的测试数据中,我有 9 个可能的 creditAccount 值,因此每天的 creditAccounts 列表不应大于 9,而是应增加总和。运行您建议的答案,我每天会在每个列表中获得数百个条目。因此,响应中的条目数量永远不会减少。
    • @FrejHåkansson 希望我现在能理解你。请检查更新的答案。
    • 您说得对,先生。我想我必须使用 unwind 但可以真正理解如何保存结果。非常感谢你是个巫师。
    猜你喜欢
    • 2017-09-03
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    • 2022-01-05
    • 2012-10-24
    • 2012-07-02
    相关资源
    最近更新 更多