web-dev-qa-db-fra.com

Obtenir un élément particulier du tableau mongoDB

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?

25
Swapnil Sonawane

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.

21
Gates VP

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

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

3
Swapnil Sonawane

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' } ] }
2
Jason Sebring