How can i get the specific matched fields values in mongodb? - mongodb

I have created one table below the table code.
use organization
db.test.insert({ bookname : "Mongodb", author : "Alex", price : 45, qty : 100})
db.test.insert({ bookname : "Cassandra", author : "John", price : 75, qty : 75})
Now I need the MongoDb and alex values when the book name is Mongodb
here we matched the bookname only remaining author name will display automaically?

What you looking is find with projection
Like this
db.test.find({ bookname: "mongodb" }, { _id: 0, bookname: 1, author: 1 })
Mongodb docs
https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/

To get one or more documents, you use -
db.test.find(<match>, <projection>)
where is the filtering part (where clause in SQL), and specifies the keys(columns in SQL tables) to return in results.
To filter the results on some field, use -
db.test.find({ "bookname" : "Mongodb" })
The above command will result all authors matching bookname as Mongodb. { "bookname" : "Mongodb" } is your match part of the command. You can modify your the find() command similar to -
db.test.find({ "bookname" : "Mongodb" }, {"bookname": 1, author: 1})
The output documents of this command will have bookname, author and _id as keys. {"bookname": 1, author: 1} is your projection part of command. For each key we want in output we set to 1 and 0 for those we don't want.
By default all keys will be in output. If you have set any key for 1 then only that key and _id will be returned. If you do not want _id then set it to 0 in projection.
db.test.find({ "bookname" : "Mongodb" }, {"bookname": 1, author: 1, _id: 0})

Related

Multiple update in a document in MongoDB

I am trying to update multiple nested documents in a document in mongoDB.
Say my data is:
{
"_id" : "ObjectId(7df78ad8902c)",
"title" : "Test",
"img_url" : "[{s: 1, v:1}, {s: 2, v: 2}, {s: 3, v: 3}]",
"tags" : "['mongodb', 'database', 'NoSQL']",
"likes" : "100"
}
I want to update v to 200 for s = 1 and s= 2 in img_url list.
It is easy to update v for any single s.
Is there any way to update multiple documents satisfying some criteria.
I tried:
db.test.update({ "_id" : ObjectId("7df78ad8902c"), "img_url.s": {$in : ["1", "2"]}}, {$set: { "img_url.$.v" : 200 } });
and
db.test.update({ "_id" : ObjectId("7df78ad8902c"), "img_url.s": {$in : ["1", "2"]}}, {$set: { "img_url.$.v" : 200 } }, {mulit: true});
Some sources are suggesting it is not possible to do so.
Multiple update of embedded documents' properties
https://jira.mongodb.org/browse/SERVER-1243
Am I missing something ?
For the specific case/example you have here. You are specifying an _id which means you are to update only one with that specific _id.
to update img_url try without the _id; something like this:
db.test.update({}, {"$set":{"img_url.0":{s:1, v:400}}}, {multi:true})
db.test.update({}, {"$set":{"img_url.1":{s:2, v:400}}}, {multi:true})
0 and 1 in img_url are the array indexes for s:1 and s:2
in order to update based on specific criteria you need to set the attribute you need on the first argument. say for example, to update all documents that have likes greater than 100 increment by 1 you do (assuming likes type is int...):
db.people.update( { likes: {$gt:100} }, {$inc :{likes: 1}}, {multi: true} )
hope that helps

Find oldest/youngest post in mongodb collection

I have a mongodb collection with many fields. One field is 'date_time', which is in an ISO datetime format, Ex: ISODate("2014-06-11T19:16:46Z"), and another field is 'name'.
Given a name, how do I find out the oldest/youngest post in the collection?
Ex: If there are two posts in the collection 'data' :
[{'name' : 'John', 'date_time' : ISODate("2014-06-11T19:16:46Z")},
{'name' : 'John', 'date_time' : ISODate("2015-06-11T19:16:46Z")}]
Given the name 'John' how do I find out the oldest post in the collection i.e., the one with ISODate("2014-06-11T19:16:46Z")? Similarly for the youngest post.
Oldest:
db.posts.find({ "name" : "John" }).sort({ "date_time" : 1 }).limit(1)
Newest:
db.posts.find({ "name" : "John" }).sort({ "date_time" : -1 }).limit(1)
Index on { "name" : 1, "date_time" : 1 } to make the queries efficient.
You could aggregate it as below:
Create an index on the name and date_time fields, so that the
$match and $sort stage operations may use it.
db.t.ensureIndex({"name":1,"date_time":1})
$match all the records for the desired name(s).
$sort by date_time in ascending order.
$group by the name field. Use the $first operator to get the first
record of the group, which will also be the oldest. Use the $last
operator to get the last record in the group, which will also be the
newest.
To get the entire record use the $$ROOT system variable.
Code:
db.t.aggregate([
{$match:{"name":"John"}},
{$sort:{"date_time":1}},
{$group:{"_id":"$name","oldest":{$first:"$$ROOT"},
"youngest":{$last:"$$ROOT"}}}
])
o/p:
{
"_id" : "John",
"oldest" : {
"_id" : ObjectId("54da62dc7f9ac597d99c182d"),
"name" : "John",
"date_time" : ISODate("2014-06-11T19:16:46Z")
},
"youngest" : {
"_id" : ObjectId("54da62dc7f9ac597d99c182e"),
"name" : "John",
"date_time" : ISODate("2015-06-11T19:16:46Z")
}
}
db.t.find().sort({ "date_time" : 1 }).limit(1).pretty()

Sorting with condition in mongodb

Here is the example collection:
[
{'name': 'element1', ratings: {'user1': 1, 'user2':2}},
{'name': 'element2', ratings: {'user1': 2, 'user2':1}}
]
I want to sort for user1: ['element2', 'element1'] ,
and for user2: ['element1', 'element2'].
In other words, I want to place the results with maximum rating for current user to top.
The collection is very big, thats why search must use indexes. The collection structure can be modified, this is just example.
Those are sorts on different fields. The first is a sort on { "ratings.user1" : -1 } and the second is a sort on { "ratings.user2" : -1 }; you will need an index on each field to support each sort. You can't scale a set up like that beyond a few users. I don't know what the entire use case is for these documents, but if the core requirement is to sort elements for a user based on the user's ratings, I would restructure the collection so that a single document represents a rating of a particular element by a particular user:
{
"_id" : ObjectId(...),
"element" : "element1",
"user" : "user1",
"rating" : 1
},
{
"_id" : ObjectId(...),
"element" : "element1",
"user" : "user2",
"rating" : 2
}
If you create an index on { "user" : 1, "rating" : -1 }, you can perform indexed queries for the ratings of elements by a particular user sorted descending by rating:
db.ratings.find({ "user" : "user1" }).sort({ "rating" : -1 })

How to query nested document in mongodb?

I have document with nested document reviews:
{
"_id" : ObjectId("53a5753937c2f0ef6dcd9006"),
"product" : "Super Duper-o-phonic",
"price" : 11000000000,
"reviews" : [
{
"user" : "fred",
"comment" : "Great!",
"rating" : 5
},
{
"user" : "Tom",
"comment" : "Great again!",
"rating" : 5
},
{
"user" : "Tom",
"comment" : "I agree with fred somewhat",
"rating" : 4
}
]
}
I want to find only those reviews whose rating is 5.
Final query should select product price and two documents from reviews whose rating is 5.
The last query I tried is :
db.testData.find({'reviews':{$elemMatch:{'rating':{$gte:5}}}}).pretty()
It's strange but it doesn't work.
How to do this in mongodb?
If you only want a single sub-doc from reviews whose rating is 5, you can use the $ positional projection operator to include the first element of reviews that matches your query:
db.test.find({'reviews.rating': 5}, {product: 1, price: 1, 'reviews.$': 1})
If you want all reviews elements with a rating of 5 (instead of just the first) you can use aggregate instead of find:
db.test.aggregate([
// Only include docs with at least one 5 rating review
{$match: {'reviews.rating': 5}},
// Duplicate the docs, one per reviews element
{$unwind: '$reviews'},
// Only include the ones where rating = 5
{$match: {'reviews.rating': 5}},
// Only include the following fields in the output
{$project: {product: 1, price: 1, reviews: 1}}])
Take a look up here: MongoDB - how to query for a nested item inside a collection?
Just in case you thought about this:
If you try to accomplish this with $elemMatchit will jsut return the first matching review.
http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/

How to write Mongo query to find sub document with condition

I have a document in a collection like this, I need to find the record with form_Id:1 and Function_Id:2, how to write the mongo query.
"Form_Id" : 1,
"Function" : [{
"Function_Id" : 1,
"Role" : [{
"Role_Id" : 1,
"UserId" : ["Admin", "001"]
}]
}, {
"Function_Id" : 2,
"Role" : [{
"Role_Id" : 2,
"UserId" : ["Admin", "005"]
}]
}]
You can use dot notation and the $ positional projection operator to do this:
db.test.find({Form_Id: 1, 'Function.Function_Id': 2}, {_id: 0, 'Function.$': 1})
returns:
{"Function": [{"Function_Id": 2, "Role": [{"Role_Id": 2, "UserId": ["Admin", "005"]}]}]}
Since your function key is an array, in order to use the $match operator, first you have to use the $unwind operator. http://docs.mongodb.org/manual/reference/aggregation/unwind/
And then you use $match operator to find the documents that you want http://docs.mongodb.org/manual/reference/aggregation/match/
So your query should look like this
db.collection.aggregate([{$unwind:"$Function"},{$match:{"Form_id":1,"Function.Function_id":2}}])
By default mongo will display the _id of the document. So if you do not want to display the _id, after matching the relevant ones, you could use the $project operator http://docs.mongodb.org/manual/reference/aggregation/project/
db.collection.aggregate([{$unwind:"$Function"},{$match:{"Form_id":1,"Function.Function_id":2}},{$project:{"_id":0,"Form_id":1,"Function":1}}])
If you don't want the form_id to be displayed, simply don't specify the form_id in the project part of the query. By default mongo will only display the keys whose value is 1. If the key is not mentioned it will not display it.
db.collection.aggregate([{$unwind:"$Function"},{$match:{"Form_id":1,"Function.Function_id":2}},{$project:{"_id":0,"Function":1}}])