涉及嵌套数组的复杂聚合查询

时间:2017-03-30 13:06:53

标签: mongodb mongodb-query aggregation-framework

我已将我的第一步移至MongoDB,但我在编写复杂查询时遇到了困难。

我的收藏中有几个这样的项目:

{
    "_id" : "sku001",
    "deposits" : [ 
        {
            "deposit_id" : "deposit01",
            "total" : "3",
            "sizes" : [ 
                {
                    "size" : "36",
                    "stock" : "2"
                }, 
                {
                    "size" : "38",
                    "stock" : "0"
                }, 
                {
                    "size" : "40",
                    "stock" : "0"
                }, 
                {
                    "size" : "42",
                    "stock" : "0"
                }, 
                {
                    "size" : "44",
                    "stock" : "0"
                }, 
                {
                    "size" : "46",
                    "stock" : "1"
                }, 
                {
                    "size" : "48",
                    "stock" : "0"
                }, 
                {
                    "size" : "50",
                    "stock" : "0"
                }, 
                {
                    "size" : "52",
                    "stock" : "0"
                }
            ]
        }, 
        {
            "deposit_id" : "deposit02",
            "total" : "5",
            "sizes" : [ 
                {
                    "size" : "36",
                    "stock" : "1"
                }, 
                {
                    "size" : "38",
                    "stock" : "1"
                }, 
                {
                    "size" : "40",
                    "stock" : "0"
                }, 
                {
                    "size" : "42",
                    "stock" : "1"
                }, 
                {
                    "size" : "44",
                    "stock" : "0"
                }, 
                {
                    "size" : "46",
                    "stock" : "1"
                }, 
                {
                    "size" : "48",
                    "stock" : "1"
                }, 
                {
                    "size" : "50",
                    "stock" : "0"
                }, 
                {
                    "size" : "52",
                    "stock" : "0"
                }
            ]
        }, 
        {
            "deposit_id" : "deposit03",
            "total" : "2",
            "sizes" : [ 
                {
                    "size" : "36",
                    "stock" : "1"
                }, 
                {
                    "size" : "38",
                    "stock" : "0"
                }, 
                {
                    "size" : "40",
                    "stock" : "0"
                }, 
                {
                    "size" : "42",
                    "stock" : "1"
                }, 
                {
                    "size" : "44",
                    "stock" : "0"
                }, 
                {
                    "size" : "46",
                    "stock" : "0"
                }, 
                {
                    "size" : "48",
                    "stock" : "0"
                }, 
                {
                    "size" : "50",
                    "stock" : "0"
                }, 
                {
                    "size" : "52",
                    "stock" : "0"
                }
            ]
        }, 
        {
            "deposit_id" : "deposit04",
            "total" : "0",
            "sizes" : [ 
                {
                    "size" : "36",
                    "stock" : "0"
                }, 
                {
                    "size" : "38",
                    "stock" : "0"
                }, 
                {
                    "size" : "40",
                    "stock" : "0"
                }, 
                {
                    "size" : "42",
                    "stock" : "0"
                }, 
                {
                    "size" : "44",
                    "stock" : "0"
                }, 
                {
                    "size" : "46",
                    "stock" : "0"
                }, 
                {
                    "size" : "48",
                    "stock" : "0"
                }, 
                {
                    "size" : "50",
                    "stock" : "0"
                }, 
                {
                    "size" : "52",
                    "stock" : "0"
                }
            ]
        }
    ]
}

并且想编写一个查询来输出这个结果文档:

{
    "_id" : "sku001",
    "total": 10,
    "sizes" [
        {
            "size" : "36",
            "stock" : "4"
        }, 
        {
            "size" : "38",
            "stock" : "1"
        }, 
        {
            "size" : "40",
            "stock" : "0"
        }, 
        {
            "size" : "42",
            "stock" : "2"
        }, 
        {
            "size" : "44",
            "stock" : "0"
        }, 
        {
            "size" : "46",
            "stock" : "2"
        }, 
        {
            "size" : "48",
            "stock" : "1"
        }, 
        {
            "size" : "50",
            "stock" : "0"
        }, 
        {
            "size" : "52",
            "stock" : "0"
        }
    ]
}

这样:

  • 总计是总数"总数"每笔存款中的字段
  • 尺寸是每个存款中相同尺寸总和的结果数组

我知道我需要将ObjectMapper mapper = new ObjectMapper(); Foo response = mapper.readValue("{\"some_key\": {\"a\": 1, \"b\": \"text\"}}", Foo.class); aggregate()$unwind$group一起使用,但我不了解如何以及以何种顺序。< / p> 你能帮帮我吗?我使用MongoDB版本3.4.3

1 个答案:

答案 0 :(得分:0)

在将聚合框架中的运算符应用于生成所需报告之前,您可能希望先更改架构,即需要将字符串值解析为数字,然后运行聚合操作。

更改架构

要更改架构,您需要迭代集合,并为集合中的每个文档更新需要将字符串值解析为数字的键。如果无法更改原始集合架构,您可能希望使用更新的架构创建临时集合。 对于前者,请考虑运行以下更新操作(对于相对较小的集合):

db.collection.find({}).snapshot()
  .forEach(function(doc) {
        var query = { "_id": doc._id },
            update = { "$set": {} };

        for (var i=0; i<doc.deposits.length; i++) {         
            update["$set"]["deposits."+i+".total"] =  parseInt(doc.deposits[i].total);          
            for (var j=0; j<doc.deposits[i].sizes.length; j++) {                
                update["$set"]["deposits."+i+".sizes."+j+".stock"] = parseInt(doc.deposits[i].sizes[j].stock);                              
            }
        }

        printjson(query);
        printjson(update);

        db.collection.updateOne( query, update );
  });

聚合管道

拥有正确的架构将允许您在以下聚合操作中运行管道,该操作应该为您提供所需的报告:

db.collection.aggregate([
    { "$unwind": "$deposits" },
    { "$unwind": "$deposits.sizes" },                
    {
        "$group": {
            "_id": { 
                "id": "$_id",                   
                "size": "$deposits.sizes.size"
            },
            "total_stock": { "$sum": "$deposits.sizes.stock" },             
            "deposits": { 
                "$push": {
                    "deposit_id": "$deposits.deposit_id",
                    "total":  "$deposits.total" 
                }
            }
        }
    },
    { "$unwind": "$deposits" },
    {
        "$group": {
            "_id": { 
                "id": "$_id.id", 
                "deposit_id": "$deposits.deposit_id"
            },
            "sizes": { 
                "$push": {
                    "size": "$_id.size",
                    "stock": "$total_stock"
                }
            },
            "total": { "$first": "$deposits.total" }
        }
    },      
    {
        "$group": {
            "_id": "$_id.id",
            "total": { "$sum": "$total" },
            "sizes": { "$first": "$sizes" }    
        }
    }
])