Summing Mongo Sub-Document Array - mongodb

db.test3.find()
{ "_id" : 1, "results" : [{"result" : {"cost" : [ { "priceAmt" : 100 } ] } } ] }
I tried the following unsucessfully:
db.test3.aggregate({$group : {_id: "", total : {$sum:
$results.result.cost.priceAmt"}}}, {$project: {_id: 0, total: 1}})
{ "result" : [ { "total" : 0 } ], "ok" : 1 }
EDIT
Desired output:
100 // sum of each "priceAmt"

You'll have to use the $unwind operator to turn array items into individual documents.
db.test3.aggregate({$unwind: "$results"}, {$unwind: "$results.result.cost"}, {$group : {_id: "", total : {$sum: "$results.result.cost.priceAmt"}}}, {$project: {_id: 0, total: 1}})
The $unwind needs to be applied twice because you have a nested array.

Related

Multiple condition in group by mongodb

I have data like this in a database:
{
"_id" : ObjectId("5ec4e40a7c89c96c7c3818f0"),
"lob" : "DIGITAL_STORE",
"paymentMode" : "NET_BANKING",
"pgStatus" : "PG_SUCCESS",
"createdAt" : ISODate("2020-05-20T08:02:18.566Z"),
"updatedAt" : ISODate("2020-07-22T18:57:29.915Z"),
"updatedBy" : "ONLINE_CHANNEL",
"_class" : "com.airtel.payments.pg.commons.persistence.PgTransactionDetails"
},
{
"_id" : ObjectId("5ec4e40a7c89c96c7c3818f0"),
"lob" : "DIGITAL_STORE",
"paymentMode" : "NET_BANKING",
"pgStatus" : "PG_FAILED",
"createdAt" : ISODate("2020-05-20T08:02:18.566Z"),
"updatedAt" : ISODate("2020-07-22T18:57:29.915Z"),
"updatedBy" : "ONLINE_CHANNEL",
"_class" : "com.airtel.payments.pg.commons.persistence.PgTransactionDetails"
}
I need to get data from mongodb where I can fetch count of success and failure in one document grouped by LOB & Payment mode.
I tried something like this, but lob and payment mode segregation not coming.
db.getCollection('transactionDetails').aggregate([
{$project: {
Success: {$cond: [{$eq: ["$pgStatus", "PG_SUCCESS" ]}, 1, 0]},
Failed: {$cond: [{$eq: ["$pgStatus", "PG_FAILED"]}, 1, 0]}
}},
{$group: {
_id: {Lob:"$lob",Mode:"$paymentMode"},
Success: {$sum: "$Success"},
Failed: {$sum: "$Failed"}
}}
]);
I can do this separately but not able to get in single document both count of success and failure transaction.
Because you have used $project and you have projected one field only and other fields are no longer available for next pipeline,
You can add other fields in $project or you can use $addFields instead of $project,
Playground
or you can try inside all operations in $group,
db.getCollection('transactionDetails').aggregate([
{
$group: {
_id: { Lob: "$lob", Mode: "$paymentMode" },
Success: {
$sum: { $cond: [{ $eq: ["$pgStatus", "PG_SUCCESS"] }, 1, 0] }
},
Failed: {
$sum: { $cond: [{ $eq: ["$pgStatus", "PG_FAILED"] }, 1, 0] }
}
}
}
])
Playground

how to find duplicate records in mongo db query to use

I have below collection, need to find duplicate records in mongo, how can we find that as below is one sample of collection we have around more then 10000 records of collections.
/* 1 */
{
"_id" : 1814099,
"eventId" : "LAS012",
"eventName" : "CustomerTab",
"timeStamp" : ISODate("2018-12-31T20:09:09.820Z"),
"eventMethod" : "click",
"resourceName" : "CustomerTab",
"targetType" : "",
"resourseUrl" : "",
"operationName" : "",
"functionStatus" : "",
"results" : "",
"pageId" : "CustomerPage",
"ban" : "290824901",
"jobId" : "87377713",
"wrid" : "87377713",
"jobType" : "IBJ7FXXS",
"Uid" : "sc343x",
"techRegion" : "W",
"mgmtReportingFunction" : "N",
"recordPublishIndicator" : "Y",
"__v" : 0
}
We can first find the unique ids using
const data = await db.collection.aggregate([
{
$group: {
_id: "$eventId",
id: {
"$first": "$_id"
}
}
},
{
$group: {
_id: null,
uniqueIds: {
$push: "$id"
}
}
}
]);
And then we can make another query, which will find all the duplicate documents
db.collection.find({_id: {$nin: data.uniqueIds}})
This will find all the documents that are redundant.
Another way
To find the event ids which are duplicated
db.collection.aggregate(
{"$group" : { "_id": "$eventId", "count": { "$sum": 1 } } },
{"$match": {"_id" :{ "$ne" : null } , "count" : {"$gt": 1} } }
)
To get duplicates from db, you need to get only the groups that have a count of more than one, we can use the $match operator to filter our results. Within the $match pipeline operator, we'll tell it to look at the count field and tell it to look for counts greater than one using the $gt operator representing "greater than" and the number 1. This looks like the following:
db.collection.aggregate([
{$group: {
_id: {eventId: "$eventId"},
uniqueIds: {$addToSet: "$_id"},
count: {$sum: 1}
}
},
{$match: {
count: {"$gt": 1}
}
}
]);
I assume that eventId is a unique id.

How to join two Aggregation results in MongoDB?

I have a data set looks as
{"BrandId":"a","SessionId":100,"Method": "POST"}
{"BrandId":"a","SessionId":200,"Method": "PUT"}
{"BrandId":"a","SessionId":200,"Method": "GET"}
{"BrandId":"b","SessionId":300,"Method": "GET"}
I wrote aggregation count distinct session id by brandid:
db.collection.aggregate([
{$group: {
"_id": {
brand: "$BrandId",
session: "$SessionId"
},
count: {$sum: 1}
}},
{$group: {
_id: "$_id.brand",
countSession:{$sum:1}
}}
])
The expected result of the query is :
{ "_id" : "a", "countSession" : 2 }
{ "_id" : "b", "countSession" : 1 }
Another query is to count where the Method is POST by brand:
db.collection.aggregate([
{$match: {Method:"POST"}},
{$group: {
_id: '$BrandId',
countPOST:{$sum:1}
}}
])
The expected result:
{ "_id" : "a", "countPOST" : 1 }
{ "_id" : "b", "countSession" : 0 }
And now, I want to combine these two query and get the expected result as following:
{"BrandId:"a","countSession":2,"countPOST":1}
{"BrandId:"b","countSession":1,"countPOST":0}
I do not how to combine these two result of two aggregation, anyone can help?
You can use $cond operator as follows.
db.Collection.aggregate(
{
'$group': {
'_id': {'BrandId':'$BrandId','Session': '$SessionId'},
'countPOST':{
'$sum':{
'$cond': [{'$eq':['$Method','POST']},1,0]
}
}
}
},
{
'$group': {
'_id': '$_id.BrandId',
'countSession': {'$sum':1},
'countPOST': {'$sum': '$countPOST'}
}
}
)
Ouput:
{
"result" : [
{
"_id" : "a",
"countSession" : 2,
"countPOST" : 1
},
{
"_id" : "b",
"countSession" : 1,
"countPOST" : 0
}
],
"ok" : 1
}

Aggregate objects' nested array occurrences count

I'm trying to aggregate logs in that way, so I can get count of how many times keywords were favorited by particular user. What I came up is following query:
db.a.aggregate([
{$unwind: "$keywords"},
{$group : {_id : {word : "$keywords", user : "$favorited_by"}, count : {$sum : 1}}}
]);
But it produces output:
{ "_id" : { "word" : "another", "user" : "too_creepy" }, "count" : 1 }
{ "_id" : { "word" : "test", "user" : "too_creepy" }, "count" : 2 }
Whilst I want to get something like this:
INPUT
{
_id: ObjectId("5475cf117ccee624583ba94a"),
favorited_by: "too_creepy",
keywords: [
"test"
]
},
{
_id: ObjectId("5475cf117ccee624583ba949"),
favorited_by: "too_creepy",
keywords: [
"test"
]
},
{
_id: ObjectId("5475cf117ccee624583ba949"),
favorited_by: "too_creepy",
keywords: [
"anotherone"
]
},
{
_id: ObjectId("5475cf117ccee624583ba09a"),
favorited_by: "hello_world",
keywords: [
"test"
]
}
OUTPUT
{
favorited_by: "too_creepy",
keywords: [
{keyword: "test", count: 2},
{keyword: "anotherone", count: 1}
]
},
{
favorited_by: "hello_world",
keywords: [
{keyword: "test", count: 1}
]
}
Any ideas how can to write this query if it's even possible?
You can do that by adding a second $group to your pipeline followed up with a final $project to reshape the output a bit:
db.a.aggregate([
{$unwind: "$keywords"},
{$group: {_id: {word: "$keywords", user: "$favorited_by"}, count: {$sum: 1}}},
// Group again on just user, and use $push to assemble an array of their keywords
{$group: {
_id: '$_id.user',
keywords: {$push: {keyword: '$_id.word', count: '$count'}}
}},
// Reshape the output
{$project: {favorited_by: '$_id', keywords: 1, _id: 0}}
]);
Output:
{
"keywords" : [
{
"keyword" : "anotherone",
"count" : 1
},
{
"keyword" : "test",
"count" : 2
}
],
"favorited_by" : "too_creepy"
},
{
"keywords" : [
{
"keyword" : "test",
"count" : 1
}
],
"favorited_by" : "hello_world"
}

group operations over arrays using Mongo aggregation framework

I'm using mongodb 2.2. I would like to use the new Aggregation Framework to do queries over my documents, but the elements are arrays.
Here an example of my $project result:
{
"type" : [
"ads-get-yyy",
"ads-get-zzz"
],
"count" : [
NumberLong(0),
NumberLong(10)
],
"latency" : [
0.9790918827056885,
0.9790918827056885
]
}
I want to group by type, so for "ads-get-yyy" to know how much is the average of count and how much is the average of the latency.
I would like to have something similar to the next query, but that works inside of the elements of every array:
db.test.aggregate(
{
$project : {
"type" : 1,
"count" : 1,
"latency" : 1
}
},{
$group : {
_id: {type : "$type"},
count: {$avg: "$count"},
latency: {$avg: "$latency"}
}
});
I'm just learning the new AF too, but I think you need to first $unwind the types so that you can group by them. So something like:
db.test.aggregate({
$project : {
"type" : 1,
"count" : 1,
"latency" : 1
}
},{
$unwind : "$type"
},{
$group : {
_id: {type : "$type"},
count: {$avg: "$count"},
latency: {$avg: "$latency"}
}
});