MongoDb Group BY MAX date and get field from this document - mongodb

Look my problen hehe. I don't know how I can do it.
There are a lot of assetState 1..n I would like do aggregation for get last asset state group by asset.
Mongo collection : assetState
[
{
"lsd" : {
"$id" : ObjectId("lucas")
},
"stateDate" : ISODate("2018-09-10T16:26:44.501Z"),
"assetId" : ObjectId("5b96b7645f2b3c0101520s60")
},
{
"lsd" : {
"$id" : ObjectId("denner")
},
"stateDate" : ISODate("2018-09-10T17:26:44.501Z"),
"assetId" : ObjectId("5b96b7645f2b3c0101520s60")
},
{
"lsd" : {
"$id" : ObjectId("denner")
},
"stateDate" : ISODate("2018-09-10T18:26:44.501Z"),
"assetId" : ObjectId("5b96b7645f2a8c0001530f61")
},
{
"lsd" : {
"$id" : ObjectId("lermen")
}
},
"stateDate" : ISODate("2018-09-10T20:26:44.501Z"),
"assetId" : ObjectId("5b96b7645f2a8c0001530f61")
},
{
"lsd" : {
"$id" : ObjectId("floripa")
},
"stateDate" : ISODate("2018-09-10T19:26:44.501Z"),
"assetId" : ObjectId("5b96b7645f2a8c0001530f61")
}
]
I would like get max "stateDate", so I need get LSD from same row(document).
Expected result:
{
"lsd" : {
"$id" : ObjectId("lermen")
},
"stateDate" : ISODate("2018-09-10T20:26:44.501Z")
}
I tried to do:
db.getCollection('assetState').aggregate([
{
$group: {
"_id": {"assetId": "$assetId"},
"stateDate": {
"$max": "$stateDate"
},
"lsd": {$last: "$lsd"} // I tried change $max to $min and $last it din't work :(
}
]);
Result:
{
"lsd" : {
"$id" : ObjectId("floripa")
},
"stateDate" : ISODate("2018-09-10T20:26:44.501Z")
}
Many Thanks

Try this query
db.getCollection('assetState').aggregate([
{$sort:{"stateDate":-1}},
]).limit(1)

you can $sort descending before $group and gets the first item of each group with $arrayElemAt
db.getCollection('assetState').aggregate([
{ $sort: { stateDate: -1 } },
{ $group: { _id: { "assetId" : "$assetId" },
states: { $push: "$$ROOT" }
}
},
{ $project: { "last_asset": { $arrayElemAt: [ "$states", 0 ] }, _id:0 } },
])
Result:
/* 1 */
{
"last_asset" : {
"_id" : ObjectId("5db2b34fa1b70230bba9c4d9"),
"lsd" : "denner",
"stateDate" : ISODate("2018-09-10T17:26:44.501Z"),
"assetId" : "5b96b7645f2b3c0101520s60"
}
}
/* 2 */
{
"last_asset" : {
"_id" : ObjectId("5db2b34fa1b70230bba9c4db"),
"lsd" : "lermen",
"stateDate" : ISODate("2018-09-10T20:26:44.501Z"),
"assetId" : "5b96b7645f2a8c0001530f61"
}
}

You could use $unwind (aggregation)
https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

I have this for the group by phase:
{
_id: {"sourceOfEvent":"$sourceOfEvent","vehicleId":"$vehicleId"},
maxTimeOfEvent: { $max: "$timeOfEvent" }
}
So group by on 2 fields and I use the max to get the max of the timeOfEvent (which is a date)

Related

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 }

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.

$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.