Mongo: Group, push and sort - node.js

I have a mongodb collection data as per below;I want to group by EmployeedID( i.e 0001) and then sort(by age)
{
"_id" : ObjectId("54d0512191a4da7736e9db43"),
"EmployeeID" : "0001",
"Speciality" : "xxx",
"Code" : "P",
"Age" : 8
}
/* 1 */
{
"_id" : ObjectId("54d0512191a4da7736e9db44"),
"EmployeeID" : "0002",
"Speciality" : "yyyyy",
"Code" : "P",
"Age" : 6
}
/* 2 */
{
"_id" : ObjectId("54d0512191a4da7736e9db45"),
"EmployeeID" : "0001",
"Speciality" : "zzz",
"Code" : "P",
"Age" : 5
}
I know I can group using the following way.
collection.aggregate([
{$match:{"EmployeeId":0001}},
{$group:{"_id":"$EmployeeID",
"speciality":{$push:"$Speciality"},
"Code":{$push:"$Code"},
"Age":{$push:"$Age"}}}
])
But how can I using $sort here? SO my result can be something like below;
[{ "EmployeeID" : "0001",
"speciality" : [ "zzz","xxx"],
"Code" :[ "P","P"],
"Age" : [5,8]
}]

You can sort the document prior to the grouping stage:
collection.aggregate([
{$sort: {_id: -1}},
{$match:{"EmployeeId":0001}},
{$group:{"_id":"$EmployeeID",
"speciality":{$push:"$Speciality"},
"Code":{$push:"$Code"},
"Age":{$push:"$Age"}}}
])

Sorting prior to grouping may exceed mongo's memory when dealing with large collections. Fortunately, you can set allowDiskUse to true to allow mongo to write temporary files.

Related

How to group a document with the same name that has different values for a specific attribute in one array using Mongodb?

If I have these objects :
{
"_id" : ObjectId("5caf2c1642e3731464c2c79d"),
"requested" : [],
"roomNo" : "E0-1-09",
"capacity" : 40,
"venueType" : "LR(M)",
"seatingType" : "TB",
"slotStart" : "8:30AM",
"slotEnd" : "9:50AM",
"__v" : 0
}
/* 2 */
{
"_id" : ObjectId("5caf2deb4a7f5222305b55d5"),
"requested" : [],
"roomNo" : "E0-1-09",
"capacity" : 40,
"venueType" : "LR(M)",
"seatingType" : "TB",
"slotStart" : "10:00AM",
"slotEnd" : "11:20AM",
"__v" : 0
}
is it possible to get something like this using aggregate in mongodb?
[{ roomNo: "E0-1-09" , availability : [{slotStart : "8:30AM", slotEnd: "9:50AM"} ,
{slotStart: "10:00AM", slotEnd : "11:20AM"}]
what im using currently:
db.getDB().collection(collection).aggregate([
{ $group: {_id:{roomNo: "$roomNo", availability :[{slotStart:"$slotStart", slotEnd:"$slotEnd"}]}}}
])
actually getting it twice like so :
[{ roomNo: "E0-1-09" , availability : [{slotStart : "8:30AM", slotEnd: "9:50AM"}]
[{ roomNo: "E0-1-09" , availability : [{slotStart: "10:00AM", slotEnd : "11:20AM"}]
You have to use $push accumulator
db.collection.aggregate([
{ "$group": {
"_id": "$roomNo",
"availability": {
"$push": {
"slotEnd": "$slotEnd",
"slotStart": "$slotStart"
}
}
}}
])

How to get sum of a particular field of a collection in MongoDB collection using PyMongo?

My MongoDB contains the following data
{
"_id" : ObjectId("5c1b742eb1829b69963029e8"),
"duration" : 12,
"cost" : 450,
"tax" : 81,
"tags" : [],
"participants" : [
ObjectId("5c1b6a8f348ddb15e4a8aac7"),
ObjectId("5c1b742eb1829b69963029e7")
],
"initiatorId" : ObjectId("5c1b6a8f348ddb15e4a8aac7"),
"context" : "coach",
"accountId" : ObjectId("5bdfe7b01cbf9460c9bb5d68"),
"status" : "over",
"webhook" : "http://d4bdc1ef.ngrok.io/api/v1/webhook_callback",
"hostId" : "5be002109a708109f862a03e",
"createdAt" : ISODate("2018-12-20T10:51:26.143Z"),
"updatedAt" : ISODate("2018-12-20T10:51:44.962Z"),
"__v" : 0,
"endedAt" : ISODate("2018-12-20T10:51:44.612Z"),
"startedAt" : ISODate("2018-12-20T10:51:32.992Z"),
"type" : "voip"
}
{
"_id" : ObjectId("5c1b7451b1829b69963029ea"),
"duration" : 1,
"cost" : 150,
"tax" : 27,
"tags" : [],
"participants" : [
ObjectId("5c1b6a8f348ddb15e4a8aac7"),
ObjectId("5c1b7451b1829b69963029e9")
],
"initiatorId" : ObjectId("5c1b6a8f348ddb15e4a8aac7"),
"context" : "coach",
"accountId" : ObjectId("5bdfe7b01cbf9460c9bb5d68"),
"status" : "over",
"webhook" : "http://d4bdc1ef.ngrok.io/api/v1/webhook_callback",
"hostId" : "5be002109a708109f862a03e",
"createdAt" : ISODate("2018-12-20T10:52:01.560Z"),
"updatedAt" : ISODate("2018-12-20T10:52:08.018Z"),
"__v" : 0,
"endedAt" : ISODate("2018-12-20T10:52:07.667Z"),
"startedAt" : ISODate("2018-12-20T10:52:06.762Z"),
"type" : "voip"
}
I want to get the total duration (sum of duration field) for a particular accountID where status is equals to "over" for a particular date range. Anyway to accomplish this using PyMongo? I am unable to form the query
Well I was doing some pretty basic mistakes while converting the query to PyMongo aggregation function. All I would say is be careful with the query structure format and especially the keys are to be encapsulated within quotes(""). To solve this all I have to do was
from bson.objectid import ObjectId
pipe = [
{"$match": {"accountId": ObjectId(accountId),
"status": "over",
"startedAt": {"$gte": startDate,
"$lte": EndDate
}
}},
{"$project": {"readableDate":
{"$dateToString":
{"format": "%Y-%m-%d", "date": "$startedAt"}},
"accountId": str("$accountId"),
"duration": "$duration"
}},
{"$group": {"_id": {"date": "$readableDate",
"accountId": str("$accountId")}, "totalCallDuration": {"$sum": "$duration"}}}]
for doc in db.VoiceCall.aggregate(pipe):
print(doc)
Just a reminder : the startDate and EndDate are in Python datetime format.

finding the parent document id based on the sub document _id of array field

Hyy , I have a collection where comments related to the blog are stored in multiple document as shown below.
[
{
"_id" : ObjectId("565f0f5d77f0c7bd11bbadd8"),
"blog_id" : ObjectId("56587befdb7224110f007233"),
"comments" : [
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "pradip is bhole baba",
"_id" : ObjectId("565f0f5d77f0c7bd11bbadd9"),
"dt" : ISODate("2015-12-02T15:33:49.578Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "honkog pokhara... he he ha ha",
"_id" : ObjectId("565f1034fd07cbfc1129db0b"),
"dt" : ISODate("2015-12-02T15:37:24.581Z")
}
],
"record_count" : 2,
"__v" : 0
}
{
"_id" : ObjectId("565efa37635f09900d21a339"),
"blog_id" : ObjectId("56587befdb7224110f007233"),
"comments" : [
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "wat a nice car wow",
"_id" : ObjectId("565efa37635f09900d21a33a"),
"dt" : ISODate("2015-12-02T14:03:35.289Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "love is life budikhola ma dives",
"_id" : ObjectId("565efa76635f09900d21a33b"),
"dt" : ISODate("2015-12-02T14:04:38.661Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "bholi ajaya ko bihe",
"_id" : ObjectId("565efaa0635f09900d21a33c"),
"dt" : ISODate("2015-12-02T14:05:20.847Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "manish is nice",
"_id" : ObjectId("565efb17635f09900d21a33d"),
"dt" : ISODate("2015-12-02T14:07:19.704Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "niroj is cool",
"_id" : ObjectId("565efd53c22dddc80e8f461c"),
"dt" : ISODate("2015-12-02T14:16:51.730Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "ramesh is cool",
"_id" : ObjectId("565f0d376d82e24c11f6c0d1"),
"dt" : ISODate("2015-12-02T15:24:39.010Z")
}
],
"record_count" : 6,
"__v" : 0
}
]
Suppose user wants to update his comment; for this I would have the comments _id now my problem is that how can I detect in which document the comment exist based of the comment _id value of comments array field.
suppose I have a comment "_id" : "565f0f5d77f0c7bd11bbadd9" (first element of first document)
then the result should give the parent document _id:"565f0f5d77f0c7bd11bbadd8" (first document id)
How can I do this..
Thank you in advance
if possible, then please update your schema.
Suppose you have collection of Blog. Then your code will be :
Blog.find({'comments._id' : '565f0f5d77f0c7bd11bbadd9'}).exec(function(err,blog){
if(!err && blog){
console.log("Blog id :"+blog._id);
}
else{
console.log("Dont get your blog");
}
});
if your comments are directly stored on the blog document you could go with an aggregate method to collect the comment across all documents. note that this seems to work when you don't have any object references to be populated.
asuming all documents are based on a blog Schema and that you wish to recieve the id of the comment:
Blog.aggregate(
[{'$match':{'comments':{'$elemMatch:{'_id':'565f0f5d77f0c7bd11bbadd9'}}}},
{'$project':{comments:'$_id', user_id:1}},
{'$unwind':'$comments'}
{'$group':{_id:'$comments'}}
]).exec(function(err, results){
if(results){
console.log(results);
}
});
I hope this is somewhat what you're looking for, you might find the following read usefull
elementMatch and aggregation from the mongoDB docs.
cheers!
The site recommended this old question to me as being Related to another I was looking at. Looks like a sufficient answer wasn't ever given, so I'll provide it for any future readers.
The requested behavior here is very straightforward to achieve with a basic find() query:
db.collection.find(
{ "comments._id": ObjectId("565f0f5d77f0c7bd11bbadd9") },
{ _id: 1 }
)
Here we are filtering the documents based on the values of the _id fields embedded in the comments array. Then for the matching document(s) we are applying a projection to just retrieve the _id field of the "parent document" (e.g. the document that was matched). If the _ids for the comments are unique then there will only ever be a maximum of a single matching document. Sample playground demonstration is here.
A more complicated aggregation would have only been necessary here if the intent was to always provide the _id value of the first document associated with a given blog_id but that does not appear to be the case here.

MongoDB remove the lowest score, node.js

I am trying to remove the lowest homework score.
I tried this,
var a = db.students.find({"scores.type":"homework"}, {"scores.$":1}).sort({"scores.score":1})
but how can I remove this set of data?
I have 200 pieces of similar data below.
{
"_id" : 148,
"name" : "Carli Belvins",
"scores" : [
{
"type" : "exam",
"score" : 84.4361816750119
},
{
"type" : "quiz",
"score" : 1.702113040528119
},
{
"type" : "homework",
"score" : 22.47397850465176
},
{
"type" : "homework",
"score" : 88.48032660881387
}
]
}
you are trying to remove an element but the statement you provided is just to find it.
Use db.students.remove(<query>) instead. Full documentation here

How to get the double quotes arround number typed field from MongoDB aggregation query result?

Scenario: I have a collection 'People' with following documents
{
"_id" : ObjectId("512bc95fe835e68f199c8686"),
"name": "David",
"age" : 78
},
{ "_id" : ObjectId("512bc962e835e68f199c8687"),
"name" : "Dave",
"age" : 35
}
When I query using following code from Node.js
db.articles.aggregate(
{ $match : { author : "Dave" } }
);
The output will be like:
{ "_id" : ObjectId("512bc962e835e68f199c8687"),
"name" : "Dave",
"age" : 35
}
Issues: The above is just a sample of the actual scenario, I want the 'age' filed value to be embedded in double quotes i.e for above quoted example it should be like "age": "35".
That is full resultant document should be like following:
{ "_id" : ObjectId("512bc962e835e68f199c8687"),
"name" : "Dave",
"age" : "35"
}
Consider I have huge number of documents how efficiently I can achieve the same to get the desired output?
Question: Can someone help out with bright and efficient way to achieve the same?

Resources