MongoDb GridFS with the existing specific collection in a database - mongodb

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 }
)

Related

In MongoDB, how to obtain only a specific field of a collection? [duplicate]

This question already has answers here:
How to filter array in subdocument with MongoDB [duplicate]
(3 answers)
Closed 2 years ago.
Lets suppose we have the following collection:
{
"_id" : 10,
"youtube_id" : "xxx",
"title" : "yyy",
"counters" : [
{
"timestamp" : 202003181300,
"views" : 7433,
"likes" : 2477,
"dislikes" : 34,
"comments" : 105
},
{
"timestamp" : 202003200815,
"views" : 12494,
"likes" : 4877,
"dislikes" : 248,
"comments" : 322
}
]
}
{
"_id" : 11,
"youtube_id" : "xxz",
"title" : "yyz",
"counters" : [
{
"timestamp" : 202003181300,
"views" : 12,
"likes" : 2,
"dislikes" : 0,
"comments" : 0
},
{
"timestamp" : 202003200815,
"views" : 198,
"likes" : 50,
"dislikes" : 4,
"comments" : 36
}
]
}
And I want to query for the number of comments given a certain timestamp and title, my guess would be to do as follows:
db.youtube.find({"title":"yyy","counters.timestamp":{$eq:202003181300}},{"_id":0,"title":1,"counters.timestamp":1,"counters.comments":1}).pretty()
And the result I am getting is the following:
{
"title" : "yyy",
"counters" : [
{
"timestamp" : 202003181300,
"comments" : 105
},
{
"timestamp" : 202003200815,
"comments" : 322
}
]
}
The problem is that I would only like to see the part that has the same timestamp I have done the query for, like this:
{
"title" : "yyy",
"counters" : [
{
"timestamp" : 202003181300,
"comments" : 105
}
]
}
Is there a way to do it, and in case I am missinterpreting what the query does could anyone give me a piece of advice? Thanks in advance
Ps. It is my first post, and I am learning the mongo basics so forgive me if I have said anything wrong.
The problem is that your "counters.timestamp":{$eq:202003181300} gets ignored, since counters is an array of subdocuments, not a subdocument itself. You can use $elemMatch query modifier like I did here:
db.youtube.find(
{
"title":"yyy","counters":{
$elemMatch: { "timestamp": { $eq: 202003181300 } }
}
},
{"_id": 0, "title": 1, "counters.timestamp": 1, "counters.comments": 1 }
).pretty()
P.S. You can omit $eq: query modifier and simply do { "timestamp": 202003181300 }.
Let me know if it works.

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"})

How do I move data using update in MongoDB?

Assuming I have a document...
{
"_id" : ObjectId("5c4cc127c33477ec8841d317"),
"review_date" : "2019-01-26T04:07:43.345Z",
"comment" : "decent product",
"score" : 4,
"reviewer_id" : "barry"
}
and I want to update it to be...
{
"_id" : ObjectId("5c4cc127c33477ec8841d317"),
"review_date" : "2019-01-26T05:15:13.122Z",
"comment" : "awesome product",
"score" : 5,
"reviewer_id" : "barry",
"history" : [
{
"review_date" : "2019-01-26T04:07:43.345Z",
"comment" : "decent product",
"score" : 4
}
]
}
How would I change this?
In other words, move/copy some of the fields to another area of the document, and replace some existing fields with new values. The purpose is to store history of change within the same document as an array - could be many review changes.
What you plan on doing is add history. You can do this by using db.collection.findOneAndUpdate with $set in place.
An example with a collection name product would be:
db.products.findOneAndUpdate({ _id: ObjectId("5c4cc127c33477ec8841d317") }, {
$set: {
score: 5,
history: [{
"review_date" : "2019-01-26T04:07:43.345Z",
"comment" : "decent product",
"score" : 4
}]
}
})

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 query insert field into document from a list of Id's

I'm kind of stuck with the following problem. I have a MongoDB filled with documents, of these documents (I have a list with Id's) I need to insert a field.
I have this document:
{
"id" : 3639,
"type" : "P",
"createdate" : "2011-10-19T11:45:14+0200",
"name_creator" : "",
"latitude" : "50.887",
"longitude" : "9.14999",
"themes" : [{
"name" : "Fun",
"id" : "4"
}, {
"name" : "Kids",
"id" : "5"
}]
}
I need a query the can insert the themes field into the document, the current themes field does not have to be updates, just 1 new one. I have over 300 Id's where this has to be done.
The document should then look like this:
(all the other fields in themes should be removed, just one new one 'Outside')
{
"id" : 3639,
"type" : "P",
"createdate" : "2011-10-19T11:45:14+0200",
"name_creator" : "",
"latitude" : "50.887",
"longitude" : "9.14999",
"themes" : [{
"name" : "Outside",
"id" : "6"
}]
}
I would normally write a bit of Java code that would loop over the documents and change them, but I believe (hope) this could be done in a query.
Anyone got an idea on how I could do this?
Thanks for any help!
All you need to do is
db.collection.update(
{id : {$in : [your list of ids]}},
{$set : {
theme : [{
"name" : "Outside",
"id" : "6"
}]
}},
{multi : true}
)