Get particular element from mongoDB array [duplicate]
I have mongo collection like below
{
"auther" : "xyz" ,
"location" : "zzz" ,
"books" :
[
{"book1" : "b1" , "date" : 2-3-00} ,
{"book1" : "b2" , "date" : 4-9-00}
]
}
{
"auther" : "pqr",
"location" : "zzz" ,
"books" :
[
{"book1" : "b1" , "date" : 2-4-00}
]
}
I want to get the only the date of book b1 and author xyz .
i have make query like below
db.coll.find({"auther" : "xyz" , "books.book1" : "b1"} , {"books.date" : 1})
but it's gives output as follows
"books" : {"date" : 2-4-00} , "books" : {"date" : 4-9-00}
I want to get the only the date of book b1 and other xyz .means only "books" : {"date" : 2-4-00}
is it possible in mongo or am I doing something wrong?
Solution 1:
The MongoDB query language is designed to return all matching Documents.
There is no support for returning only sub-documents.
This issue has an outstanding ticket in MongoDB's ticket tracker.
UPDATE: it looks like the ticket has been marked as fixed.
See here for an example of how to use this.
Solution 2:
It can be done using map/reduce, just emit the sub element into a temporary inline collection. Its a Hack and it works however I'd advise against it as map/reduce is single threaded, and has a large overhead for what you want to achieve, it is much easier to just extract the sub-element in your application.
Something like this...
map:
m = function() {
this.books.forEach(function(book){
if(book1 == 'b1'){
emit("books", {date: book.date,});
}
});
}
reduce:
r = function(key, values) {
return this;
}
query:
db.coll.mapReduce(m, r, {query : {"auther" : "xyz" , "books.book1" : "b1"}, out: { inline : 1}})
Solution 3:
if you want to select only matching element you can query like this.
b.coll.find({"auther" : "xyz" , "books.book1" : "b1"},{"books.$.date" : 1})
Solution 4:
With a little imagination (pre mongo v 2.6) ...
You can do this with aggregate or map reduce. Aggregate is newer, easier and more optimized. Here's a sample of returning a sub document with aggregate assuming your collection is named "Authors". I took the liberty of spelling things correctly.
Authors.aggregate([
{ $match: { author: 'xyz' } },
{ $unwind: '$books' },
{
$project: {
_id: '$books.book1',
date: '$books.date'
}
},
{ $match: { '$_id' : 'b1' } }
]);
You'll get back an array with a single entry like so:
[{ _id: 'b1', date: '2-4-00' }]
Otherwise, if mongo 2.6+ you can do the really easy way:
Authors.find({
author: 'xyz',
books: { $elemMatch: { book1: 'b1' } }
},'books')
Where you will get back the books collection if found and only a single record within:
{ _id: 'xyz', books: [ { book1: 'b1', date: '2-4-00' } ] }