Please explain this mongodb query and its result - mongodb

The query goes as follows
db.restaurants.find({$and : [{"grades.score" : {$gt:80}},{"grades.score" : {$lt:100}}]})
it was written with the idea in mind of retrieving restaurants with a score of 80 to 100
why does this query return the following document in its result. the below document does not have any grade element in the grades sub-document which falls in the range of "greater than 80 AND less than 100".
i have tried using this
{
"_id" : ObjectId("572eb5df1d739cc73c21fab1"),
"address" : {
"building" : "65",
"coord" : [
-73.9782725,
40.7624022
],
"street" : "West 54 Street",
"zipcode" : "10019"
},
"borough" : "Manhattan",
"cuisine" : "American ",
"grades" : [
{
"date" : ISODate("2014-08-22T00:00:00Z"),
"grade" : "A",
"score" : 11
},
{
"date" : ISODate("2014-03-28T00:00:00Z"),
"grade" : "C",
"score" : 131
},
{
"date" : ISODate("2013-09-25T00:00:00Z"),
"grade" : "A",
"score" : 11
},
{
"date" : ISODate("2013-04-08T00:00:00Z"),
"grade" : "B",
"score" : 25
},
{
"date" : ISODate("2012-10-15T00:00:00Z"),
"grade" : "A",
"score" : 11
},
{
"date" : ISODate("2011-10-19T00:00:00Z"),
"grade" : "A",
"score" : 13
}
],
"name" : "Murals On 54/Randolphs'S",
"restaurant_id" : "40372466"
}

This happens because both conditions are true. When you don't specify indices for grades.score it search through all elements of the array. And it does find an item with score > 80 (which is 131). At the same time there exist other items that are less then 100.
In human language you request "a document that contains score greater then 80 and at the same time contains score less then 100". You don't specify that it should be the same score that satisfy these conditions.
What you're looking for I guess is a query for simultaneously checking range for each element.
{ "grades" : { $elemMatch: { score: { $gt:80, $lt:100 } } } }

Yeah as said by #Kirill Slatin, your both conditions are true in that case. So, for your required result, check out the following solution with an explanation for your better understanding:
Using $lte and $gte separately,
db.products.find({score:{$gt:'80'}})
db.products.find({score:{$lt:'100'}})
First statement will return the result with score of 80 and gretaer than 80 and Second statement will return the score results with 100 and less than 100
Using $lt and $gt together
db.products.find({score:{$gt:80,$lt:100}})
The above Query will return the score results greater than 80 and less than 100

Related

How to query element in array of arrays in MongoDB?

I'm learning MongoDB on my own. I have a collection with entries that look like this:
{
"_id" : ObjectId("5d0c13fbfdca455311248d6f"),
"borough" : "Brooklyn",
"grades" :
[
{ "date" : ISODate("2014-04-16T00:00:00Z"), "grade" : "A", "score" : 5 },
{ "date" : ISODate("2013-04-23T00:00:00Z"), "grade" : "B", "score" : 2 },
{ "date" : ISODate("2012-04-24T00:00:00Z"), "grade" : "A", "score" : 5 }
],
"name" : "C & C Catering Service",
"restaurant_id" : "40357437"
}
And I want to find all restaurants in Brooklyn with at least one grades.grade of A.
I've figured out the first half of the puzzle:
db.restaurants.find({borough:{$eq:"Brooklyn"}})
But how do I query in the "grades" array for grade A?
Use dot (.) to access and query nested objects:
db.restaurants.find({'borough':{$eq:"Brooklyn"}, 'grades.grade': 'A'})
db.restaurants.find({"borough" : "Brooklyn","grades.grade":"A"})

MongoDB and aggragate the embeded document

I am new to mongoDB and I came across a problem. The data was imported according to official doc.
As you can see, each of restaurant has a grades array and the nested document contains a score field. What I want to do is according to the average score of each restaurant's grades and retrive the restaurant that has the top average score. This may need to use mongoDB's aggregate method but the document doesn't cover the nested document situation and I googled but without a result. There's a similar question on this site but it's not so clear.
[
{ "_id" : ObjectId("56a9f39cae1902590811dffc"),
"address" : { "building" : "284",
"coord" : [ -73.9829239, 40.6580753 ],
"street" : "Prospect Park West",
"zipcode" : "11215" },
"borough" : "Brooklyn",
"cuisine" : "American ",
"grades" : [ { "date" : ISODate("2014-11-19T00:00:00Z"), "grade" : "A", "score" : 11 },
{ "date" : ISODate("2013-11-14T00:00:00Z"), "grade" : "A", "score" : 2 },
{ "date" : ISODate("2012-12-05T00:00:00Z"), "grade" : "A", "score" : 13 },
{ "date" : ISODate("2012-05-17T00:00:00Z"), "grade" : "A", "score" : 11 } ],
"name" : "The Movable Feast",
"restaurant_id" : "40361606" },
...
]
Using the mongo shell, try the below , change "collecttionname" to the name of your your restaurant collections
db.collectionname.aggregate( { '$unwind' : '$grades' } , { '$group' : { '_id' : '$_id' , 'average' : { $avg : '$grades.score' } } } , { '$sort' : { 'average' : -1 } } , { '$limit' : 1 } )

MongoDB Max, Sort, and Limit

I'm attempting to use find (not aggregation) to give me the max score by student on a test. Essentially would be a sort by student, find top score for that student, then sort the result set. Here is the data:
{ "_id" : 1, "name" : "Pat", "score" : 97 }
{ "_id" : 1, "name" : "Pat", "score" : 92 }
{ "_id" : 2, "name" : "Pat", "score" : 89 }
{ "_id" : 3, "name" : "Ken", "score" : 91 }
{ "_id" : 4, "name" : "Ken", "score" : 81 }
I'm looking for the result to look like this (where only the students top score is returned):
{ "_id" : 1, "name" : "Pat", "score" : 97 }
{ "_id" : 2, "name" : "Ken", "score" : 91 }
I've tried many different combinations but can't get it to work. I know in SQL how I'd do it. Here is my current code, which is just sorting it:
db.grades.find().sort({score: -1})
You can use:
db.grades.find().sort('-score').distinct('name').sort('score')

MongoDb GridFS with the existing specific collection in a database

Consider the below "restaurants" collection documents in the "restaurant" mongodb database.
{
"_id" : ObjectId("55f6564073fc0a09338cf434"),
"address" : {
"building" : "97-22",
"coord" : [
-73.8601152,
40.7311739
],
"street" : "63 Road",
"zipcode" : "11374"
},
"borough" : "Queens",
"cuisine" : "Jewish/Kosher",
"grades" : [
{
"date" : ISODate("2014-11-23T17:30:00.000-06:30"),
"grade" : "Z",
"score" : 20
},
{
"date" : ISODate("2013-01-16T17:30:00.000-06:30"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2012-08-01T17:30:00.000-06:30"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2011-12-14T17:30:00.000-06:30"),
"grade" : "B",
"score" : 25
},
........
.......
.......
{
"date" : ISODate("2011-12-14T17:30:00.000-06:30"),
"grade" : "AZZ",
"score" : 25
}, -- It reaches 15 MB
],
"name" : "Tov Kosher Kitchen",
"restaurant_id" : "40356068"
}
In this document "grades" filed is the embedded document array. This array is going to reach mongodb maximum document size 16Mb. So now we are in the situation to alter the data model for this collection. I came to know that in the mongoDb we can store the documents which exceed the default limit of 16mb by using "gridfs" . I'm not able to find the links to demonstrate this. I need to store gridfs documents along with existing fields in the collection.
Just because you can embed documents, it doesn't mean that it's always a good idea. More often than not, it isn't.
Markus W Mahlberg
It basically only works in a "One-to-(Very-)Few" relationship. In your case, it's different.
Ask the right question. What do you really want to know? My guess is
What are the grades for a given restaurant?
So, modeling becomes easy. First, a restaurants collection
{
_id: someObjectId,
name: "The Foo Bar",
cuisine: "Foo and Baz",
...
}
and a grades collection:
{
_id: new ObjectId(),
restaurant: someObjectId,
grade: "A",
date: someISODate
}
Answering the question is nothing more than:
db.grades.find(
{ restaurant: givenRestaurantsObjectId }
)

using aggregation in 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"}
}}
);