2016-04-14 5 views
0

Ich versuche in Sub-Dokumenten zu suchen. Das ist meine Struktur meines Dokuments:MongoDB - Subdokumente suchen

{ 
    _id: <ObjectID>, 
    email: ‘[email protected]’, 
    password: ‘12345’, 
    images: [ 
     { 
      title: ‘Broken Hand’, 
      description: ‘Here is a full description’, 
      comments: [ 
       { 
        comment: ‘Looks painful’, 
       } 
      ], 
      tags: [‘hand’, ‘broken’] 
     } 
    ] 
} 

und ich möchte alle Bilder von allen Benutzern zu finden in der Lage sein, die einen bestimmten Tag, aber die Abfrage ich nur verwendet, wird das erste Bild der Rückkehr mit, dass findet tag:

Kann mir bitte jemand in die richtige richtung zeigen, wie ich alle bilder bekommen kann?

+0

Ihre elem Übereinstimmung scheint in der Projekt-Sektion statt der Filter-Sektion zu sein (Aber ich könnte mich irren). Versuchen Sie: 'db.site_users.find ({'images.tags':" kaputt ", {images: {$ elemMatch: {'tags': 'kaputt'}}}, {images: 1}). Pretty()' ? –

Antwort

0

Sie können die aggregation framework dafür verwenden:

db.site_users.aggregate([ 
    {$unwind: "$images"}, 
    {$match:{ 
     "images.tags": "broken" 
    }} 
]) 
0

Die Abfrage ist gut, wie es das Dokument übereinstimmt, aber die „Projektion“ ist außerhalb des Rahmens, was Sie mit .find() tun können, müssen Sie .aggregate() und etwas Sorgfalt darauf verwendet, die "Bilder" -Elemente nicht aus dem Array zu entfernen und nur die nicht passenden "Tags".

Idealer Sie tun dies mit MongoDB 3.2 mit $filter innen $project:

db.site_users.aggregate([ 
    { "$match": { "images.tags": "broken" }}, 
    { "$project": { 
     "email": 1, 
     "password": 1, 
     "images": { 
      "$filter": { 
       "input": "$images", 
       "as": "image", 
       "cond": { 
        "$setIsSubSet": [["broken"], "$$image.tags"] 
       } 
      } 
     } 
    }} 
]) 

Oder vielleicht $map und $setDifference verwendet, die ebenfalls mit MongoDB 2.6, solange die „Bilder“ Inhalt „einzigartig“ ist kompatibel für jeder Eintrag. Dies ist aufgrund der „set“ Operation, bei der „Sets“ sind „einzigartig“:

db.site_users.aggregate([ 
    { "$match": { "images.tags": "broken" }}, 
    { "$project": { 
     "email": 1, 
     "password": 1, 
     "images": { 
      "$setDifference": [ 
       { "$map": { 
        "input": "$images", 
        "as": "image", 
        "in": { 
         "$cond": { 
          "if": { "$setIsSubSet": [["broken"], "$$image.tags" ] }, 
          "then": "$$image", 
          "else": false 
         } 
        } 
       }}, 
       [false] 
      ] 
     } 
    }} 
]) 

Es kann in früheren Versionen von MongoDB getan werden, aber möglicherweise aufgrund der Kosten für die Verarbeitung am besten vermieden $unwind auf die Array:

db.site_users.aggregate([ 
    { "$match": { "images.tags": "broken" }}, 
    { "$unwind": "$images" }, 
    { "$match": { "images.tags": "broken" }}, 
    { "$group": { 
     "_id": "$_id", 
     "email": { "$first": "$email" }, 
     "password": { "$first": "$password" }, 
     "images": { "$push": "$images" } 
    }}  
]) 

Da es bei der Verwendung $unwind zu diesem Zweck in der Regel eine erhebliche Kosten ist, wo Sie nicht alles „Aggregation“, dann, wenn Sie, wo die anderen praktische Ansätze zur Verfügung keine moderne Version haben, ist es oft am besten, um den Array-Inhalt selbst im Client-Code und nicht auf dem Server zu "filtern".

Sie sollten also nur auf $unwind für diesen Fall zurückgreifen, wo die Array-Einträge "erheblich" reduziert werden würden, um die nicht übereinstimmenden Elemente zu entfernen. Andernfalls sind die Verarbeitungskosten wahrscheinlich höher als die Netzwerkkosten für die Übertragung der Daten, und jeder Vorteil wird negiert.

Wenn Sie keine moderne Version haben, dann holen Sie sich eine. Die Eigenschaften machen den Unterschied zu praktisch und performant.

Verwandte Themen