J'ai une collection de mongo comme ci-dessous
{
"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}
]
}
Je veux obtenir la seule date du livre b1 et de l'auteur xyz.
j'ai faire une requête comme ci-dessous
db.coll.find({"auther" : "xyz" , "books.book1" : "b1"} , {"books.date" : 1})
mais il donne la sortie comme suit
"books" : {"date" : 2-4-00} , "books" : {"date" : 4-9-00}
Je veux obtenir la seule date du livre b1 et d'autres xyz. Signifie uniquement "books" : {"date" : 2-4-00}
est-ce possible à mongo ou est-ce que je fais quelque chose de mal?
Le langage de requête MongoDB est conçu pour renvoyer tous les documents correspondants.
Il n'y a pas de support pour renvoyer uniquement les sous-documents.
Ce problème a un ticket en attente dans le tracker de ticket de MongoDB.
MISE À JOUR: il semble que le ticket ait été marqué comme corrigé.
Voir ici pour un exemple d'utilisation.
Cela peut être fait en utilisant map/Reduce, il suffit d'émettre le sous-élément dans une collection en ligne temporaire. C'est un Hack et cela fonctionne, mais je le déconseille car Map/Reduce est un thread unique et a un gros frais généraux pour ce que vous voulez réaliser, il est beaucoup plus facile d'extraire simplement le sous-élément dans votre application.
Quelque chose comme ça...
carte:
m = function() {
this.books.forEach(function(book){
if(book1 == 'b1'){
emit("books", {date: book.date,});
}
});
}
réduire:
r = function(key, values) {
return this;
}
requete:
db.coll.mapReduce (m, r, {query: {"auther": "xyz", "books.book1": "b1"}, out: {inline: 1}})
si vous souhaitez sélectionner uniquement l'élément correspondant, vous pouvez interroger comme ceci.
b.coll.find ({"auther": "xyz", "books.book1": "b1"}, {"books. $. date": 1})
Avec un peu d'imagination (pre mongo v 2.6) ...
Vous pouvez le faire avec un agrégat ou une réduction de carte. L'agrégat est plus récent, plus facile et plus optimisé. Voici un exemple de renvoi d'un sous-document avec agrégat en supposant que votre collection est nommée "Auteurs". J'ai pris la liberté de bien orthographier les choses.
Authors.aggregate([
{ $match: { author: 'xyz' } },
{ $unwind: '$books' },
{
$project: {
_id: '$books.book1',
date: '$books.date'
}
},
{ $match: { '$_id' : 'b1' } }
]);
Vous récupérerez un tableau avec une seule entrée comme ceci:
[{ _id: 'b1', date: '2-4-00' }]
Sinon, si mongo 2.6 + vous pouvez faire le moyen vraiment simple:
Authors.find({
author: 'xyz',
books: { $elemMatch: { book1: 'b1' } }
},'books')
Où vous récupérerez la collection de livres si elle est trouvée et un seul enregistrement dans:
{ _id: 'xyz', books: [ { book1: 'b1', date: '2-4-00' } ] }