[英]$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.