Reputation: 403
I have a document with entries like this
{
"_id": ObjectId("5644c495d0807a1750043237"),
"siteid": "123456"
"amount": 1.32
}
Some documents have other amounts eg."cashbackAmount"
I want a sum
and a count
for each amount fields. Not every document contains all the amount fields.
I hjave tried the following
{
$group: {
"_id": "$siteid",
item2: { "$sum": "$amount" },
item3: { "$sum": "$totalAmount" },
item4: { "$sum": "$cashbackAmount" },
item5: { "$sum": "$unitPrice" },
}
}
It gives me the sum, but I cannot work out how to get the number times each amount field is present.
{ "$sum": 1 }
does not work because that gives me all the documents that have any one of the totals fields.
Upvotes: 2
Views: 1849
Reputation: 35408
I guess you probably want something like that
db.getCollection('amounts').aggregate([
{
$project: {
siteid: 1,
amount: 1,
totalAmount: 1,
unitPrice: 1,
cashbackAmount: 1,
amountPresent: {
$cond: {
if: "$amount",
then: 1,
else: 0
}
},
totalAmountPresent: {
$cond: {
if: "$totalAmount",
then: 1,
else: 0
}
},
cashbackAmountPresent: {
$cond: {
if: "$cashbackAmount",
then: 1,
else: 0
}
},
unitPricePresent: {
$cond: {
if: "$unitPrice",
then: 1,
else: 0
}
}
}
},
{
$group: {
"_id": "$siteid",
amountSum: { "$sum": "$amount" },
amountCount: { "$sum": "$amountPresent" },
totalAmountSum: { "$sum": "$totalAmount" },
totalAmountCount: { "$sum": "$totalAmountPresent" },
cashbackAmountSum: { "$sum": "$cashbackAmount" },
cashbackAmountCount: { "$sum": "$cashbackAmountPresent" },
unitPriceSum: { "$sum": "$unitPrice" },
unitPriceCount: { "$sum": "$unitPricePresent" }
}
}
])
Upvotes: 1
Reputation: 103445
If you know the amount fields in advance then you could do this in a single aggregation operation where you create the pipeline dynamically.
Check out the following demonstration:
var amountFields = ["amount", "totalAmount", "cashbackAmount", "unitPrice"],
groupOperator = { "$group": { "_id": "$siteid" } };
amountFields.forEach(function (field){
groupOperator["$group"][field+"Total"] = { "$sum": "$"+field };
groupOperator["$group"][field+"Count"] = {
"$sum": {
"$cond": [ { "$gt": [ "$"+field, null ] }, 1, 0 ]
}
};
});
db.test.aggregate([groupOperator]);
Populate Test Documents
db.test.insert([
{
"siteid": "123456",
"amount": 1.32
},
{
"siteid": "123456",
"cashbackAmount": 8.32
},
{
"siteid": "123456",
"cashbackAmount": 9.74
},
{
"siteid": "123456",
"unitPrice": 0.19
},
{
"siteid": "123456",
"amount": 27.8,
"totalAmount": 15.22,
"unitPrice": 5.10,
"cashbackAmount": 43.62
},
{
"siteid": "123456",
"unitPrice": 5.07
},
{
"siteid": "123456",
"amount": 12.98,
"totalAmount": 32.82
},
{
"siteid": "123456",
"amount": 6.65,
"unitPrice": 5.10
}
])
Sample Aggregation Output
{
"_id" : "123456",
"amountTotal" : 48.75,
"amountCount" : 4,
"totalAmountTotal" : 48.04,
"totalAmountCount" : 2,
"cashbackAmountTotal" : 61.68,
"cashbackAmountCount" : 3,
"unitPriceTotal" : 15.46,
"unitPriceCount" : 4
}
Upvotes: 1