Can not get $sum in aggregate function in MongoDB - mongodb

Here's my data format :
"request" : {
"_id" : 1003,
"user" : {
"username" : "",
"password" : "",
"_id" : 1111,
"gender" : "male",
},
"request" : {
"merchantid" : "TA456",
"txnAmount" : 18000,
"fee" :0,
"IssuerID" : "18801111",
"bankID" : "888888",
}
},
"confirmation" : true
}`
I can not get the sum of 'request.request.txnAmount' group by 'request.user._id'.
Here's my query:
db.getCollection('megabank_response').aggregate(
[ { $group : {
_id : "request.user._id",
totalPrice: { $sum: "request.request.txnAmount"},
count: { $sum: 1 }
}
}
])
And get the result :
{
"_id" : "request.user._id",
"total Price" : 0,
"count" : 4.0
}
Can anyone help me why my query cannot calculate the sum?

You seem to missing the $ symbol in the group aggregation function.
db.megabank_response.aggregate([{
$group: {
_id: "request.user._id",
ss: {
$sum: "request.request.txnAmount"
}
}
}]);
gives: { "_id" : "request.user._id", "ss" : 0 }
But the correct answer is:
db.megabank_response.aggregate([{
$group: {
_id: "$request.user._id",
ss: {
$sum: "$request.request.txnAmount"
}
}
}]);

I've managed to figured out the query using answer from this source.
However, my query is stil a little bit too messy. Any ways to optimize it?
db.getCollection('megabank_response').aggregate([
{
"$match": {
"request.user._id": 1111
}
},
{
"$group":{
_id : "request.user._id",
totalPrice: { $sum: '$request.request.txnAmount'},
count: { $sum: 1 }
}
}
])
Result:
{
"_id" : "request.user._id",
"totalPrice" : 62000,
"count" : 3.0
}

Try:
db.getCollection('megabank_response').aggregate([{
$group: {
_id : "request.user._id",
totalPrice: { $sum: "$request.request.txnAmount"},
count: { $sum: 1 }
}
}])

You can also use totalPrice: { $sum: "$txnAmount"} to display the sum of your transaction amount. I was working on the GET request of Total Sales in the e-shop that I developed, and I had faced the same issue. Just for your reference, here is my code:
//GET total sales data for the ADMIN
router.get('/get/totalsales', async(req, res) => {
const totalSales = await Order.aggregate([
{ $group: { _id: null, totalSales : { $sum: '$totalPrice' }}} // Use $totalPrice instead of totalPrice
])
if(!totalSales) {
return res.status(400).send('The sales cannot be generated')
}
res.send({totalSales: totalSales})
})
Hope this helps :)

Related

$group with $map not working properly in mongodb

I am new to mongodb aggregation, i have a collection
{
"_id":60ab3312623b0108338a9601,
"items":[{"type":"Tshirt","price":300,"quantity":2}],
"orderId":"ORD189",
"from":"abc",
"to":"xyz",
"createdAt":2021-05-24T05:01:06.960Z,
"__v":0,
"tracking":null
}
I want to find the count of orders per day and totalPrice of items like
{_id: {date:24, month:05, year:2021}, count: 1, totalPrice: 600}
I used aggregations like below
db.getCollection("orders").aggregate(
[
{
"$group" : {
"_id" : {
"date" : {
"$dayOfMonth" : "$createdAt"
},
"month" : {
"$month" : "$createdAt"
},
"year" : {
"$year" : "$createdAt"
}
},
"count" : { $sum : 1},
"totalPrice" : {
$sum: {
$map: {
"input" :"$items",
"as":"item",
"in":{
$multiply: ["$item.price", "$item.quantity"]
}
}
}
}
}
}
]
);
It is giving me the following result
{
"_id" : {
"date" : NumberInt(24),
"month" : NumberInt(5),
"year" : NumberInt(2021)
},
"count" : 1.0,
"totalPrice" : NumberInt(0)
}
If I use unwind am not able to get the proper count.
You just need to correct totalPrice calculation,
$map to iterate loop of items and do multiplication of price and quantity, this will return array of total
$sum to get total of above total
"totalPrice": {
$sum: {
$sum: {
$map: {
input: "$items",
in: {
$multiply: ["$$this.price", "$$this.quantity"]
}
}
}
}
}
Playground

I'm having trouble with a mongodb function that should be finding duplicates

I have the following function that is supposed to be returning the _id value of duplicates based on the email key. However, no matter what I've tried, I can't get the function to return anything other than any empty object. What am I missing here? Or is there a better approach I should be considering?
var duplicates = [];
db.medicallists
.aggregate([
{
$group: {
_id: {
email: "$email"
},
duplicate_ids: { $addToSet: "$_id" },
count: { $sum: 1 }
}
},
{
$match: {
count: { $gt: 1 }
}
},
], { allowDiskUse: true })
.forEach(function(doc) {
doc.duplicate_ids.shift(); // First element skipped for deleting
doc.duplicate_ids.forEach(function(dupId) {
duplicates.push(dupId); // Getting all duplicate ids
});
});
printjson(duplicates);
EDIT:
Here is a sample document:
{
_id : 5a2fed0c8023cf7ea2346067,
primary_spec : "Addiction Medicine",
first_name : "John",
last_name : "Sample",
city : "Las Vegas",
state : "NV",
phone : "1111111111",
fax : "1111111111",
email : "sample#aol.com"
}
I have tested your specific query on a similar data set and it works fine. printjson(duplicates); prints out all the duplicate ids.
Also this will, in fact, remove all the duplicate entries based on email:
db.collection.aggregate([
{
$group: {
_id: {
email: "$email"
},
duplicate_ids: {
$push: "$_id"
},
count: {
$sum: 1
}
}
},
{
$match: {
count: {
$gt: 1
}
}
},
]).forEach(function(doc){
doc.duplicate_ids.shift();
db.collection.remove({
_id: {
$in: doc.duplicate_ids
}
});
})
My starting set was:
{
"_id" : ObjectId("6014331de1ef9ab1f708ddd9"),
"item" : "card",
"email" : "zzz#yahoo.com"
}
{
"_id" : ObjectId("6014331de1ef9ab1f708ddda"),
"item" : "card",
"email" : "eee#yahoo.com"
}
{
"_id" : ObjectId("6014331de1ef9ab1f708dddb"),
"item" : "card",
"email" : "zzz#yahoo.com"
}
{
"_id" : ObjectId("6014331de1ef9ab1f708dddc"),
"item" : "card",
"email" : "aaa#yahoo.com"
}
After running the query, it turned to:
{
"_id" : ObjectId("6014331de1ef9ab1f708ddd9"),
"item" : "card",
"email" : "zzz#yahoo.com"
}
{
"_id" : ObjectId("6014331de1ef9ab1f708ddda"),
"item" : "card",
"email" : "eee#yahoo.com"
}
{
"_id" : ObjectId("6014331de1ef9ab1f708dddc"),
"item" : "card",
"email" : "aaa#yahoo.com"
}
Tested on MongoDB server version: 4.2.7

MongoDB nested group by query

I want to count correct, incorrect and unattempted question count. I am getting zero values.
Query -
db.studentreports.aggregate([
{ $match: { 'groupId': 314 } },
{ $unwind: '$questions' },
{ $group:
{
_id: {
dateTimeStamp: '$dateTimeStamp',
customerId: '$customerId'
},
questions : { $push: '$questions' },
unttempted : { $sum : { $eq: ['$questions.status',0]}},
correct : { $sum : { $eq: ['$questions.status',1]}},
incorrect : { $sum : { $eq: ['$questions.status',2]}},
Total: { $sum: 1 }
}
}
])
Schema structure -
{
"_id" : ObjectId("59fb46ed560e1a2fd5b6fbf4"),
"customerId" : 2863318,
"groupId" : 309,
"questions" : [
{
"questionId" : 567,
"status" : 0,
"_id" : ObjectId("59fb46ee560e1a2fd5b700a4"),
},
{
"questionId" : 711,
"status" : 0,
"_id" : ObjectId("59fb46ee560e1a2fd5b700a3")
},
....
values unttempted, correct and incorrect are getting wrong -
"unttempted" : 0,
"correct" : 0,
"incorrect" : 0,
"Total" : 7558.0
Group by is required based on datetime and customerId.
Can some one correct query ?
Thanks.
You want to sum these fields only if a certain condition is met.
You just have to rewrite your group statement like this:
{ $group:
{
_id: {
dateTimeStamp: '$dateTimeStamp',
customerId: '$customerId'
},
questions : { $push: '$questions' },
unttempted : { $sum : {$cond:[{ $eq: ['$questions.status',0]}, 1, 0]}},
correct : { $sum : {$cond:[{ $eq: ['$questions.status',1]}, 1, 0]}},
incorrect : { $sum : {$cond:[{ $eq: ['$questions.status',2]}, 1, 0]}},
Total: { $sum: 1 }
}
}
Check out the documentation $eq. $eq compares and returns true or false. So then your $sum cannot do anything with that result

mongodb aggregate and group with push

I am trying to push the data who is having minSalary using $push at group aggregate.
Query:
db.users.aggregate([
{ $match: { experience: { $gte:3, $lte:10} } },
{ $group: { _id: {totalExperience:"$experience"}, "count": {$sum:1},"minSalary": {$min:"$expected_salary"}, "minUsers": {$push:"$_id"}, "maxSalary": {$max:"$expected_salary"} } },
{ $sort: { '_id.totalExperience': -1 } }
])
Result
{
"_id" : {
"totalExperience" : 9
},
"count" : 549.0,
"minSalaryCount" : 120000,
"maxSalary" : 180000
}
Also i am expecting following result
{
"_id" : {
"totalExperience" : 9
},
"count" : 549.0,
"minSalaryCount" : 120000,
"maxSalary" : 180000,
"minSalaryUsers":[
ObjectId('5355345345sdrrw234234'),
ObjectId('5355345345sdeee234234'),
ObjectId('5355345345sdertw234234')
]
}
Thank you.

Get record of another field with aggregate

I am new in MongoDB world.
I've following data in my collection
{
"_id" : ObjectId("5735d8d4d147aa34e440988f"),
"DeviceLogId" : "26962",
"DeviceId" : "10",
"UserId" : "78",
"LogDateTime" : ISODate("2016-05-12T07:52:44.000+0000")
}
{
"_id" : ObjectId("5735d8d4d147aa34e4409890"),
"DeviceLogId" : "26963",
"DeviceId" : "10",
"UserId" : "342",
"LogDateTime" : ISODate("2016-05-12T07:54:09.000+0000")
}
{
"_id" : ObjectId("5735d8d4d147aa34e4409891"),
"DeviceLogId" : "26964",
"DeviceId" : "10",
"UserId" : "342",
"LogDateTime" : ISODate("2016-05-12T07:54:10.000+0000")
}
{
"_id" : ObjectId("5735d8d4d147aa34e4409892"),
"DeviceLogId" : "26965",
"DeviceId" : "10",
"UserId" : "78",
"LogDateTime" : ISODate("2016-05-12T07:54:27.000+0000")
}
I want to query DeviceId of each user with maximum LogDateTime using group by.
I've written group by query like below but have no idea how would I get DeviceLogId for each record.
collectionName.aggregate(
[{
$match: { LogDateTime: { $gt: todaysDateStart, $lt: todayDateEnd } }
}, {
$group: {
_id: "$UserId",
maxPunchTime: { $max: { $add: [ "$LogDateTime", 330*60000 ] } },
}
}])
In MSSQL, I could easily do it with nested query but I've no idea how would I achieve that in MongoDB.
Thanks in advance.
Use the $addToSet Group Accumulator:
collectionName.aggregate(
[{
$match: { LogDateTime: { $gt: todaysDateStart, $lt: todayDateEnd } }
}
, {
$group: {
_id: "$UserId",
maxPunchTime: { $max: { $add: [ "$LogDateTime", 330*60000 ] } },
deviceLogIds:{$addToSet: "$DeviceLogId"} //<----
}
} ,
{ $sort: {"maxPunchTime" : -1} } , {$limit : 1} //Sort Descending + Limit to 1
])
Add deviceid to an array in group phase,
Device:{$addToSet:deviceId}