mongodb aggregate and group with push - mongodb

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.

Related

Multiple grouping in mongodb

Sample Colloection Data :
{
"_id" : ObjectId("5f30df23243ffsdfwer3d14568bf"),
"value" : {
"busId" : 200.0,
"status" : {
"code" : {
"id" : 1.0,
"key" : "2100",
"value" : "Complete"
}
}
}
}
My Query does provides the right result, but would like to squeeze the output more by using multiple grouping or $project or any other aggregators.
mongo Query:
db.suraj_coll.aggregate([
{
$addFields: {
"value.available": {
$cond: [
{
$in: [
"$value.status.code.value",
[
"Accept",
"Complete"
]
]
},
"Approved",
"Rejected"
]
}
}
},
{
"$group": {
"_id": {
busID: "$value.busId",
status: "$value.available"
},
"subtotal": {
$sum: 1
}
}
}
])
Output:
/* 1 */
{
"_id" : {
"busID" : 200.0,
"status" : "Approved"
},
"subtotal" : 3.0
}
/* 2 */
{
"_id" : {
"busID" : 200.0,
"status" : "Rejected"
},
"subtotal" : 1.0
}
Is it possible to squeeze the output more by using any further grouping ?
Output should look like below
{
"_id" : {
"busID" : 200.0,
"Approved" : 3.0
"Rejected" : 1.0
}
}
tried with $project, by keeping the count in a doc , but couldn't place the count against Approve or Rejected.
Any suggestion would be great.
You can use more two pipelines after your query,
$group by busID and push status and count in status
$project to convert status array to object using $arrayToObject and merge with busID using $mergeObjects
{
$group: {
_id: "$_id.busID",
status: {
$push: {
k: "$_id.status",
v: "$subtotal"
}
}
}
},
{
$project: {
_id: {
$mergeObjects: [
{ busID: "$_id" },
{ $arrayToObject: "$status" }
]
}
}
}
Playground

MongoDB get user which are new today

I am trying to find a user list which is new for day-1. I have written the query to find the users who arrived till the day before yesterday and the list of users arrived yesterday. Now I want minus those data how can I do that in a single aggregate function.
Function to get the list before yesterday
db.chat_question_logs.aggregate([
{
$match : {"createdDate":{$lte: ISODate("2020-04-29T00:00:00Z")}}
},
{
"$project" :
{
_id : 0,
"userInfo.userId":1
}
},
{
"$group": {
"_id": {userId:"$userInfo.userId"},"count": {$sum : 1}}
}
])
similarly for the day-1 is as below
db.chat_question_logs.aggregate([
{
$match : {"createdDate":{$gte: ISODate("2020-04-30T00:00:00Z"),$lte: ISODate("2020-05-01T00:00:00Z")}}
},
{
"$project" :
{
_id : 0,
"userInfo.userId":1
}
},
{
"$group": {
"_id": {userId:"$userInfo.userId"},"count": {$sum : 1}}
}
])
Result JSON are as below
/* 1 */
{
"_id" : {
"userId" : "2350202241750776"
},
"count" : 1
},
/* 2 */
{
"_id" : {
"userId" : "26291570771793121"
},
"count" : 1
},
/* 3 */
{
"_id" : {
"userId" : "2742872209107866"
},
"count" : 5
},
/* 4 */
{
"_id" : {
"userId" : "23502022417507761212"
},
"count" : 1
},
/* 5 */
{
"_id" : {
"userId" : "2629157077179312"
},
"count" : 43
}
How can I find the difference.
It sounds like what you want is to get all users created yesterday (which is the 28th in this example).
db.chat_question_logs.aggregate([
{
$match : { $and: [
{ "createdDate":{$lt: ISODate("2020-04-29T00:00:00Z")} },
{ "createdDate": {$gte: ISODate("2020-04-28T00:00:00Z") }}
] }
},
{
"$project" :
{
_id : 0,
"userInfo.userId":1
}
},
{
"$group": {
"_id": {userId:"$userInfo.userId"},"count": {$sum : 1}}
}
])
Is this what you want?
Hi found the solution which is below
I used the group and first appearance of the Id and then filter record on date which I wanted.The query is as below
db.chat_question_logs.aggregate([
{
$group:
{
_id: "$userInfo.userId",
firstApprance: { $first: "$createdDate" }
}
},
{
$match : { "firstApprance": { $gte: new ISODate("2020-05-03"), $lt: new ISODate("2020-05-05") } }
}
])

How to group by multiple object elements

I have sample data like below
[
{
brand:"iphone",
category:"mobile"
},
{
brand:"iphone",
category:"laptop"
},
{
brand:"lenova",
category:"laptop"
}
]
and expecting result as
[
{
brand:"iphone",
count:2
},
{
brand:"lenova",
count:1
},
{
category:"laptop",
count:2
},
{
category:"mobile",
count:1
}
]
Here I want group by same object with multiple fields and get there count. Can any one please let me how to do that in the mongoose.
I am not familiarised with Mongoose. Just tried in Mongoshell
db.getCollection('test').aggregate([
{
$group:{
_id:"$brand",
brand:{$first:"$brand"},
category:{$first:"$category"}
}
},
{$project:{_id:0}}
])
Possible only by using two queries.
Group By Brand
db.getCollection('pages').aggregate([
{
$group: {_id: "$brand", category: { $push: "$category" }}
},
{
$project : {
_id : 0, brand : "$_id", count : {$size : "$category"}
}
},
{ $unwind: { path: "$category", preserveNullAndEmptyArrays: true } }
])
Result:-
/* 1 */
{
"brand" : "lenova",
"count" : 1
}
/* 2 */
{
"brand" : "iphone",
"count" : 2
}
Group By Category
db.getCollection('pages').aggregate([
{
$group: {
_id: "$category", brand: { $push: "$brand" },
}
},
{
$project : {
_id : 0, category : "$_id", count : {$size : "$brand"}
}
},
{ $unwind: { path: "$brand", preserveNullAndEmptyArrays: true } },
])
Result:-
/* 1 */
{
"category" : "laptop",
"count" : 2
}
/* 2 */
{
"category" : "mobile",
"count" : 1
}
Merge them for the required output.
We can use $facet to run parallel aggregation on data.
The following query can get us the expected output:
db.collection.aggregate([
{
$facet:{
"brand_group":[
{
$group:{
"_id":"$brand",
"brand":{
$first:"$brand"
},
"count":{
$sum:1
}
}
},
{
$project:{
"_id":0
}
}
],
"category_group":[
{
$group:{
"_id":"$category",
"category":{
$first:"$category"
},
"count":{
$sum:1
}
}
},
{
$project:{
"_id":0
}
}
]
}
},
{
$project:{
"array":{
$concatArrays:["$brand_group","$category_group"]
}
}
},
{
$unwind:"$array"
},
{
$replaceRoot:{
"newRoot":"$array"
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5da5c0d0795c8651a7f508c2"),
"brand" : "iphone",
"category" : "mobile"
}
{
"_id" : ObjectId("5da5c0d0795c8651a7f508c3"),
"brand" : "iphone",
"category" : "laptop"
}
{
"_id" : ObjectId("5da5c0d0795c8651a7f508c4"),
"brand" : "lenova",
"category" : "laptop"
}
Output:
{ "brand" : "lenova", "count" : 1 }
{ "brand" : "iphone", "count" : 2 }
{ "category" : "laptop", "count" : 2 }
{ "category" : "mobile", "count" : 1 }

$sum arrays with the same ids in mongodb

The two documents of my collection look like this:
First document
{
"_id" : 2055,
"counervalues" : {
"chcounter" : 3
"bscounter" : 10
}
"attributionvalues" :[
{
"id" : 1
"conversionvalue" : 85.0
"conversioncounter" : 6300.0
},
{
"id" : 2
"conversionvalue" : 25.0
"conversioncounter" : 600
}
}
Second document
{
"_id" : 1046,
"counervalues" : {
"chcounter" : 23
"bscounter" : 46
}
"attributionvalues" :[
{
"id" : 1
"conversionvalue" : 15.0
"conversioncounter" : 275.0
},
{
"id" : 2
"conversionvalue" : 65.0
"conversioncounter" : 12000.0
}
}
Now I want to apply the aggregation framework in order to get a new document which has a result as this:
Result
{
"_id" : 3005,
"counervalues" : {
"chcounter" : 26
"bscounter" : 56
}
"attributionvalues" :[
{
"id" : 1
"conversionvalue" : 100.0
"conversioncounter" : 6575.0
},
{
"id" : 2
"conversionvalue" : 90.0
"conversioncounter" : 12600.0
}
}
I started my aggregation like this:
db.conversion.counters.aggregate({
$match:
{
"_id" : {"$gte" : 1046 , "$lte" : 2055}
}
$group:
{
cvchc: {$sum: "$counervalues.chcounter"}
cvbsc: {$sum: "$counervalues.bscounter"}
}
});
but I have trouble to match the attributionvalues according to their ids and add them.
Anyone has an idea?
Run the following aggregation pipeline, should give you the desired results:
db.conversion.aggregate([
{ "$match": { "_id" : { "$gte" : 1046 , "$lte" : 2055 } } },
{ "$unwind": "$attributionvalues" },
{
"$group": {
"_id": "$attributionvalues.id",
"cvchc": { "$sum": "$counervalues.chcounter" },
"cvbsc": { "$sum": "$counervalues.bscounter" },
"avcv": { "$sum": "$attributionvalues.conversionvalue" },
"avcc": { "$sum": "$attributionvalues.conversioncounter" }
}
},
{
"$group": {
"_id": null,
"chcounter": { "$first": "$cvchc" },
"bscounter" : { "$first": "$cvbsc" },
"attributionvalues": {
"$push": {
"id": "$_id",
"conversionvalue": "$avcv" ,
"conversioncounter": "$avcc"
}
}
}
},
{
"$project": {
"counervalues": {
"chcounter": "$chcounter",
"bscounter": "$bscounter"
},
"attributionvalues": 1
}
}
])

MongoDB : I have a debit/credit collection and need balance of each user

I have a collection of transactions : sender_id, receiver_id, amount.
{
"_id": {
"$oid": "55279f6c1a7f98030043ddf3"
},
"sender_id": "00001",
"receiver_id": "00002",
"amount": 10000,
"__v": 0
}
For a given user, I can get the sum where he is receiver : his credits
Transaction.aggregate(
{ $match : {sender_id : user.id} },
{ $group : { _id : "$sender_id", total : { $sum : "$amount" } } },
function(err, result){
....
}
);
Replacing "receiver" with "sender" and I get his debits :
Transaction.aggregate(
{ $match : {receiver_id : user.id} },
{ $group : { _id : "$receiver_id", total : { $sum : "$amount" } } },
function(err, result){
....
}
);
So I can process ( credits - debits ) and have his balance
Transaction.aggregate(
{ $match : {receiver_id : user.id} },
{ $group : { _id : "$receiver_id", total : { $sum : "$amount" } } },
function(err, received){
Transaction.aggregate(
{ $match : {sender_id : user.id} },
{ $group : { _id : "$sender_id", total : { $sum : "$amount" } } },
function(err, sent){
received[0] - sent[0] // Balance
}
);
}
);
I would like to :
Improve and have the balance in 1 request
Get a list of my users and their balance
I have relational databases experience and maybe I think to much this way, not enough Mongo way.
Thanks
Use the following aggregation:
db.transaction.aggregate([
{ "$match" : { "$or" : [{ "sender_id" : user.id }, { "receiver_id" : user.id }] } },
{ "$project" : {
"user" : { "$cond" : [{ "$eq" : ["$sender_id", user_id] }, "$sender_id", "$receiver_id" ] },
"amount" : { "$cond" : [{ "$eq" : ["$sender_id", user_id] }, { "$multiply" : [-1, "$amount"] }, "$amount" ] }
} },
{ "$group" : { "_id" : "$user", "balance" : { "$sum" : "$amount" } } }
])
This aggregation gives wrong results if, for some reason, a user is both the sender and receiver on a single transaction, but it can be modified to handle that case as well. It's worth doing that to make sure you understand what's going on.