簡體   English   中英

通過匹配數組mongodb中的字段獲得$ sum

[英]$sum by matching fields in array mongodb

我對mongodb的經驗不足,因此以下查詢對我來說很困難。

這是文件

[
{
    "_id": "31-07-2019",
    "date": "31-07-2019",
    "grocerie1": [
        {
            "name": "Flour",
            "price": 3.68,
            "count": 1
        },
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        },
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        },
        {
            "name": "Flour",
            "price": 3.68,
            "count": 1
        }
    ],
    "grocerie2": [
        {
            "name": "Flour",
            "price": 3.68,
            "count": 1
        }
    ],
    "grocerie1Total": 13.36,
    "grocerie2Total": 3.68,
    "total": 17.04
},
{
    "_id": "09-08-2019",
    "date": "09-08-2019",
    "grocerie1": [
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        },
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        },
        {
            "name": "Milk",
            "price": 5,
            "count": 1
        }
    ],
    "grocerie2": [
        {
            "name": "Milk",
            "price": 5,
            "count": 1
        },
        {
            "name": "Cheese",
            "price": 2,
            "count": 1
        }
    ],
    "grocerie1Total": 11,
    "grocerie2Total": 7,
    "total": 18
},
{
    "_id": "22-08-2019",
    "date": "22-08-2019",
    "grocerie1": [
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        },
        {
            "name": "Cheese",
            "price": 2,
            "count": 1
        },
        {
            "name": "Cheese",
            "price": 2,
            "count": 1
        },
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        }
    ],
    "grocerie2": [
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        },
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        },
        {
            "name": "Rice",
            "price": 3,
            "count": 1
        }
    ],
    "grocerie1Total": 10,
    "grocerie2Total": 9,
    "total": 19
}
]

該文檔按日期排序,包含兩個雜貨店,每個雜貨店出售不同的產品。 每個產品都有一個名稱,價格和一個“計數”,我以后將通過該字段的總和獲得該產品的銷售次數。

現在,我要實現以下目標:

[
{
    "_id": "31-07-2019",
    "date": "31-07-2019",
    "grocerie1": [
        {
            "name": "Flour",
            "total": 7.56,
            "count": 2
        },
        {
            "name": "Rice",
            "total": 6,
            "count": 2
        }
    ],
    "grocerie2": [
        {
            "name": "Flour",
            "total": 3.68,
            "count": 1
        }
    ],
    "grocerie1Total": 13.36,
    "grocerie2Total": 3.68,
    "total": 17.04
},
{
    "_id": "09-08-2019",
    "date": "09-08-2019",
    "grocerie1": [
        {
            "name": "Rice",
            "total": 6,
            "count": 2
        },
        {
            "name": "Milk",
            "total": 5,
            "count": 1
        }
    ],
    "grocerie2": [
        {
            "name": "Milk",
            "total": 5,
            "count": 1
        },
        {
            "name": "Cheese",
            "total": 2,
            "count": 1
        }
    ],
    "grocerie1Total": 11,
    "grocerie2Total": 7,
    "total": 18
},
{
    "_id": "22-08-2019",
    "date": "22-08-2019",
    "grocerie1": [
        {
            "name": "Rice",
            "total": 6,
            "count": 2
        },
        {
            "name": "Cheese",
            "total": 4,
            "count": 2
        }
    ],
    "grocerie2": [
        {
            "name": "Rice",
            "total": 9,
            "count": 3
        }
    ],
    "grocerie1Total": 10,
    "grocerie2Total": 9,
    "total": 19
}
]

例如,我為“ grocerie1”嘗試了類似的操作,但是結果卻很糟糕:

{
    $unwind:
    {
       path: "$grocerie1",
       preserveNullAndEmptyArrays: true
    }
},
{
    "$group": {

    "_id": "$grocerie1.name",
    "eatHereInfo": { 
       "$push": { 
          "name": "$grocerie1.name", 
          "total": { "$sum": "$grocerie1.price" }, 
          "count": { "$sum": "$grocerie1.count" } } 
    },
    "grocerie2": { "$first": "$grocerie2" },
    "date": { "$first": "$date" },
    "grocerie1Total": { "$first": "$grocerie1Total" },
    "grocerie2Total": { "$first": "$grocerie2Total" },
   }
},

聚合框架有什么方法可以實現? 或使用javascript? 任何幫助和建議,表示贊賞:)

注意:我假設您的對象存儲在grocerie集合中。

Mongo方式困難而僵化

db.getCollection('grocerie').aggregate([
    // ---------------- We start with grocerie1 ------------------
    //1. Split grocerie1 array into atomic object
    {"$unwind":{ "path": "$grocerie1", "preserveNullAndEmptyArrays": true }},
    //2. Group by date + grocerie1 name. If group only by grocerie1.name we may group from other days 
    // For same grocerie names, we accumulate their name, price, total "grocerie1": { "$push": "$grocerie1" },
    {"$group": {
        "_id": { "_id": "$_id", "name": "$grocerie1.name" },
        "grocerie1": { "$push": "$grocerie1" },
        "grocerie2": { "$first": "$grocerie2" },
        "date": { "$first": "$date" },
        "grocerie1Total": { "$first": "$grocerie1Total" },
        "grocerie2Total": { "$first": "$grocerie2Total" }
        }
    },
    //3. Now we have unique date + grocerie1 names + all same items inside grocerie1 array. Split again into atomic value
    {"$unwind":{ "path": "$grocerie1", "preserveNullAndEmptyArrays": true }},

    //4. We group again date + grocerie1 names, but now we sum price and count
    {"$group": {
       "_id": { "_id": "$date", "name": "$_id.name" },
        "total": { "$sum": "$grocerie1.price" },
        "count": { "$sum": "$grocerie1.count" },
        "grocerie2": { "$first": "$grocerie2" },
        "date": { "$first": "$date" },
        "grocerie1Total": { "$first": "$grocerie1Total" },
        "grocerie2Total": { "$first": "$grocerie2Total" }
      }
    },
    //5. We group for date and push inside grocerie1 calculated price, total
    {"$group":{
        "_id": "$_id._id",
        "grocerie1": { "$push": {
            "name" : "$_id.name",
            "total" : "$total",
            "count" : "$count"
            } },
        "grocerie2": { "$first": "$grocerie2" },
        "date": { "$first": "$date" },
        "grocerie1Total": { "$first": "$grocerie1Total" },
        "grocerie2Total": { "$first": "$grocerie2Total" }
        }
     },
     // ---------------- We finished with grocerie1 ---------------
     // ---------------- We start with grocerie2 ------------------
     //1. Split grocerie2 array into atomic object
    {"$unwind":{ "path": "$grocerie2", "preserveNullAndEmptyArrays": true }},
    //2. Group by date + grocerie2 name. If group only by grocerie2.name we may group from other days 
    // For same grocerie names, we accumulate their name, price, total "grocerie2": { "$push": "$grocerie2" },
    {"$group": {
        "_id": { "_id": "$_id", "name": "$grocerie2.name" },
        "grocerie1": { "$first": "$grocerie1" },
        "grocerie2": { "$push": "$grocerie2" },
        "date": { "$first": "$date" },
        "grocerie1Total": { "$first": "$grocerie1Total" },
        "grocerie2Total": { "$first": "$grocerie2Total" }
        }
    },
    //3. Now we have unique date + grocerie2 names + all same items inside grocerie2 array. Split again into atomic value
    {"$unwind":{ "path": "$grocerie2", "preserveNullAndEmptyArrays": true }},

    //4. We group again date + grocerie2 names, but now we sum price and count
    {"$group": {
       "_id": { "_id": "$date", "name": "$_id.name" },
        "total": { "$sum": "$grocerie2.price" },
        "count": { "$sum": "$grocerie2.count" },
        "grocerie1": { "$first": "$grocerie1" },
        "date": { "$first": "$date" },
        "grocerie1Total": { "$first": "$grocerie1Total" },
        "grocerie2Total": { "$first": "$grocerie2Total" }
      }
    },
    //5. We group for date and push inside grocerie2 calculated price, total
    {"$group":{
        "_id": "$_id._id",
        "grocerie1": { "$first": "$grocerie1" },
        "grocerie2": { "$push": {
            "name" : "$_id.name",
            "total" : "$total",
            "count" : "$count"
            } },
        "date": { "$first": "$date" },
        "grocerie1Total": { "$first": "$grocerie1Total" },
        "grocerie2Total": { "$first": "$grocerie2Total" },
        // Sum total values
        "total" : {"$sum":{"$add":["$grocerie1Total", "$grocerie2Total"]}}
        }
     }
     // ---------------- We finished with grocerie2 ---------------
])

Javascript方式輕松靈活

/**
 * Group groceries with same name and sum fields
 */
function groupGroceries(){
    //aux function to group groceries with same name
    function _(grocerie){
        for(var i=grocerie.length-1; i > -1; i--){
            for(var j=0; j<i; j++){
                // If grocerie.name already exists, we sum values and remove from array
                if(grocerie[j].name == grocerie[i].name){
                    grocerie[j].price += grocerie[i].price;
                    grocerie[j].count += grocerie[i].count;
                    grocerie.splice(i, 1);
                    break;
                }
            }
        }

        //Change price into total
        for(var i=0; i<grocerie.length; i++){
            //Robo 3T bug: (""+grocerie[i].price).indexOf(".") > -1 ? grocerie[i].price : NumberInt(grocerie[i].price);
            grocerie[i].total = grocerie[i].price;
            delete grocerie[i].price;
        }
    }

    var result = [];

    //Iterate over grocerie collection
    db.getCollection('grocerie').find({}).forEach(function(doc){
        //Uncomment line below if _id disappears
        //doc["_id"];
        _(doc.grocerie1);
        _(doc.grocerie2);
        doc.total = doc.grocerie1Total + doc.grocerie2Total;
        result.push(doc);
    })

    for(var i=0; i<result.length; i++){
        print("/* " + (i+1) + " */")
        print(result[i])
        print("")
    }
}

groupGroceries();

== 結果 ==

/* 1 */
{
    "_id" : "31-07-2019",
    "grocerie1" : [ 
        {
            "name" : "Flour",
            "total" : 7.36,
            "count" : 2
        }, 
        {
            "name" : "Rice",
            "total" : 6,
            "count" : 2
        }
    ],
    "grocerie2" : [ 
        {
            "name" : "Flour",
            "total" : 3.68,
            "count" : 1
        }
    ],
    "date" : "31-07-2019",
    "grocerie1Total" : 13.36,
    "grocerie2Total" : 3.68,
    "total" : 17.04
}

/* 2 */
{
    "_id" : "09-08-2019",
    "grocerie1" : [ 
        {
            "name" : "Rice",
            "total" : 6,
            "count" : 2
        }, 
        {
            "name" : "Milk",
            "total" : 5,
            "count" : 1
        }
    ],
    "grocerie2" : [ 
        {
            "name" : "Milk",
            "total" : 5,
            "count" : 1
        }, 
        {
            "name" : "Cheese",
            "total" : 2,
            "count" : 1
        }
    ],
    "date" : "09-08-2019",
    "grocerie1Total" : 11,
    "grocerie2Total" : 7,
    "total" : 36
}

/* 3 */
{
    "_id" : "22-08-2019",
    "grocerie1" : [ 
        {
            "name" : "Cheese",
            "total" : 4,
            "count" : 2
        }, 
        {
            "name" : "Rice",
            "total" : 6,
            "count" : 2
        }
    ],
    "grocerie2" : [ 
        {
            "name" : "Rice",
            "total" : 9,
            "count" : 3
        }
    ],
    "date" : "22-08-2019",
    "grocerie1Total" : 10,
    "grocerie2Total" : 9,
    "total" : 19
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM