using aggregation in mongodb - mongodb

I have following records in mongodatabase.
> db.student.find()
{ "_id" : ObjectId("52ca76140e468ba197e50c23"), "name" : "pratik", "subject" : "maths", "marks" : 68 }
{ "_id" : ObjectId("52ca762b0e468ba197e50c24"), "name" : "pratik", "subject" : "biology", "marks" : 96 }
{ "_id" : ObjectId("52ca77a90e468ba197e50c25"), "name" : "pratik", "subject" : "maths", "marks" : 40 }
From this record I want to know the total marks obtained for just maths subject.
Here is what I have tried,but I don't know what is going wrong in the following query.
db.student.aggregate(
{$match: { 'subject': "maths"}},
{ $group : { _id :{ name:"$name",subject:"$subject",marks:"$marks" },
total: { $sum : "$marks"}}
})
{
"result" : [
{
"_id" : {
"name" : "pratik",
"subject" : "maths",
"marks" : 40
},
"total" : 40
},
{
"_id" : {
"name" : "pratik",
"subject" : "maths",
"marks" : 68
},
"total" : 68
}
],
"ok" : 1
}
Could you please let me know what has went wrong in the above query along with the correct answers.
Also suggest me the appropriate guide to use the aggregation module so that I can use it efficiently.I am beginner to aggregation module of mongo database.
Thanks in Advance.

The problem is the marks field in the group within the _id. It will group upon mark scores then which is useless to you, instead you want:
db.student.aggregate(
{$match: { 'subject': "maths"}},
{$group : {
_id :{ name:"$name", subject:"$subject" },
total: { $sum : "$marks"}
}}
);

Related

Mongodb embedded document - aggregation query

I have got the below documents in Mongo database:
db.totaldemands.insert({ "data" : "UKToChina", "demandPerCountry" :
{ "from" : "UK" , to: "China" ,
"demandPerItem" : [ { "item" : "apples" , "demand" : 200 },
{ "item" : "plums" , "demand" : 100 }
] } });
db.totaldemands.insert({ "data" : "UKToSingapore",
"demandPerCountry" : { "from" : "UK" , to: "Singapore" ,
"demandPerItem" : [ { "item" : "apples" , "demand" : 100 },
{ "item" : "plums" , "demand" : 50 }
] } });
I need to write a query to find the count of apples exported from UK to any country.
I have tried the following query:
db.totaldemands.aggregate(
{ $match : { "demandPerCountry.from" : "UK" ,
"demandPerCountry.demandPerItem.item" : "apples" } },
{ $unwind : "$demandPerCountry.demandPerItem" },
{ $group : { "_id" : "$demandPerCountry.demandPerItem.item",
"total" : { $sum : "$demandPerCountry.demandPerItem.demand"
} } }
);
But it gives me the output with both apples and plums like below:
{ "_id" : "apples", "total" : 300 }
{ "_id" : "plums", "total" : 150 }
But, my expected output is:
{ "_id" : "apples", "total" : 300 }
So, How can I modify the above query to return only the count of apples exported from UK ?
Also, is there any other better way to achieve the output without unwinding ?
You can add another $match to get only apples.
As you have embedded document structure and performing aggregation, $unwind is required here. The alternate option could be map and reduce. However, unwind is most suitable here.
If you are thinking about performance, unwind shouldn't cause performance issue.
db.totaldemands.aggregate(
{ $match : { "demandPerCountry.from" : "UK" ,
"demandPerCountry.demandPerItem.item" : "apples" } },
{ $unwind : "$demandPerCountry.demandPerItem" },
{ $group : { "_id" : "$demandPerCountry.demandPerItem.item",
"total" : { $sum : "$demandPerCountry.demandPerItem.demand"
} } },
{$match : {"_id" : "apples"}}
);

Mongodb sort by sum of keys

I have a json document
{
{
"_id" : ObjectId("5715c4bbac530eb3018b456a"),
"content_id" : "5715c4bbac530eb3018b4569",
"views" : NumberLong(200),
"likes" : NumberLong(100),
"comments" : NumberLong(0)
},
{
"_id" : ObjectId("5715c4bbac530eb3018b4568"),
"content_id" : "5715c4bbac530eb3018b4567",
"views" : NumberLong(300),
"likes" : NumberLong(200),
"comments" : NumberLong(0)
},
{
"_id" : ObjectId("5715c502ac530ee5018b4956"),
"content_id" : "5715c502ac530ee5018b4955",
"views" : NumberLong(500),
"likes" : NumberLong(0),
"comments" : NumberLong(200)
}
}
How can we sort the document order by SUM("views", "likes", "comments")
something like in mysql
SELECT SUM(key1, key2, key3) AS key
FROM document
ORDER BY key
Thanks in advance.
First do a projection to obtain the sum of all the likes, views and comments, then sort based on that sum. I am considering group by content_id if is needed in the second snippet
db.test.aggregate([
{ $project : { "_id" : "$content_id", "total" : { $add : [ "$likes", "$views", "$comments"]}}},
{ $sort : { "total" : 1 }}
])
If you need a group operation if content_id can be duplicated
db.test.aggregate([
{ $project : { "_id" : "$content_id", "total" : { $add : [ "$likes", "$views", "$comments"]}}},
{ $group : { "_id" : "$_id" , totalPerId : { $sum : "$total" }}},
{ $sort : { "total" : 1 }}
])
Based on your test data, you will get:
{ "_id" : "5715c502ac530ee5018b4955", "totalPerId" : NumberLong(700) }
{ "_id" : "5715c4bbac530eb3018b4567", "totalPerId" : NumberLong(500) }
{ "_id" : "5715c4bbac530eb3018b4569", "totalPerId" : NumberLong(300) }

MongoDB Aggregation - return default value for documents that don't match query

I'm having trouble figuring out the right aggregation pipe operations to return the results I need.
I have a collection similar to the following :-
{
"_id" : "writer1",
"Name" : "writer1",
"Website" : "website1",
"Reviews" : [
{
"Film" : {
"Name" : "Jurassic Park",
"Genre" : "Action"
},
"Score" : 4
},
{
"Technology" : {
"Name" : "Mad Max",
"Genre" : "Action"
},
"Score" : 5
}
]
}
{
"_id" : "writer2",
"Name" : "writer2",
"Website" : "website1",
"Reviews" : [
{
"Technology" : {
"Name" : "Mad Max",
"Genre" : "Action"
},
"Score" : 5
}
]
}
And this is my aggregation so far : -
db.writers.aggregate([
{ "$unwind" : "$Reviews" },
{ "$match" : { "Reviews.Film.Name" : "Jurassic Park" } },
{ "$group" : { "_id" : "$Website" , "score" : { "$avg" : "$Reviews.Score" },
writers :{ $push: { name:"$Name", score:"$Reviews.Score" } }
}}
])
This returns only writers who have a review of the matching film and also only websites that have at least 1 writer who has reviewed the film,
however, I need to return all websites containing a list of their all writers, with a score of 0 if they haven't written a review for the specified film.
so, I am currently getting : -
{ "_id" : "website1", "score" : 4, "writers" : [ { "name" : "writer1", "score" : 4 } ] }
When I actually need : -
{ "_id" : "website1", "score" : 2, "writers" : [ { "name" : "writer1", "score" : 4 },{ "name" :"writer2", "score" : 0 } ] }
Can anyone point me in the right direction?
Cheers

JasperReports MongoDB Query How to access subdocument?

We have a document stored in MongoDB which looks like this:
{
"id" : 1,
"name" : "demo-name",
"lastModified" : ISODate("2015-01-07T07:19:35Z"),
"snapshot" : {
"rows" : [
{
"quantity" : 100,
"rate" : 32,
"description" : "22MM SHROUDED PBA RED",
"productCatlgNo" : "3MA40 00 AA0"
},
{
"quantity" : 125,
"rate" : 32,
"description" : "22MM SHROUDED PBA BLACK",
"productCatlgNo" : "3MA40 01 AA0"
}
]
}
}
I am trying to access this document and read only the data stored in the snapshot.rows in JasperStudio report designer using the following query:
{
'collectionName' : 'views.abcdefghi',
'findQuery' : {
'name': 'demo-name'
},
'findFields':{
'snapshot.rows': 1
}
}
But the output contains only snapshot.rows whereas I want the inner details of the documents present in the rows.
How should I go about it?
This could be your answer (based on this link)
}
runCommand:
{
aggregate : 'views.abcdefghi',
pipeline :
[
{$match : {"name" : "demo-name"}},
{$project : {"rows" : "$snapshot.rows" }},
]
}
}
after running the command (on sample document) db.test.aggregate([ {$project : {"rows" : "$snapshot.rows"}} ]).result in mongo shell I had this result (just ids and rows):
{
"0" : {
"_id" : ObjectId("54b9017ec283f0c25c9cbf5e"),
"rows" : [
{
"quantity" : 100,
"rate" : 32,
"description" : "22MM SHROUDED PBA RED",
"productCatlgNo" : "3MA40 00 AA0"
},
{
"quantity" : 125,
"rate" : 32,
"description" : "22MM SHROUDED PBA BLACK",
"productCatlgNo" : "3MA40 01 AA0"
}
]
}
}

mongodb find all records with subdocument id equals to

i have the following collection records:
> db.products.find(ObjectId("53a9a6aad901f2961403fc9b")).pretty()
{
"_id" : ObjectId("53a9a6aad901f2961403fc9b"),
"code" : "N39",
"name" : {
"en-UK" : "N39"
},
"weight" : [
90
],
"collectionId" : ObjectId("53a9a6a8d901f2961403fbe2"),
"fabric_composition" : [
{
"fabricId" : ObjectId("53a9a6a9d901f2961403fc69"),
"value" : 70
}
{
"fabricId" : ObjectId("53a9a6a9d901f2961403fc6a"),
"value" : 30
}
],
"visible" : "true",
"manufacturer" : "53a859d9d901f2e8f81ac83b"
}
and
> db.fabric.find().pretty()
{
"_id" : ObjectId("53a9a6a9d901f2961403fc69"),
"name" : [
{
"en-UK" : "Recycled Organic Cotton"
}
]
}
{
"_id" : ObjectId("53a9a6a9d901f2961403fc6a"),
"name" : [
{
"en-UK" : "Recycled Polyester"
}
]
}
how do i query the mongodb collection products to list all products that have a fabric_composition with ObjectId for Recycled Organic Cotton as an example?
any advice much appreciated
You need to use use dot notation to query subdocuments:
db.products.find({
"fabric_composition.fabricId" : ObjectId("53a9a6a9d901f2961403fc69")
});
This query will return all documents that have at least one sub-document with fabricId you're looking for.