MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDb :Gemeinsames Element aus zwei Arrays innerhalb einer Abfrage finden

Es gibt ein paar Ansätze, um das zu tun, was Sie wollen, es hängt nur von Ihrer Version von MongoDB ab. Senden Sie einfach die Shell-Antworten. Der Inhalt ist im Grunde eine JSON-Darstellung, die für DBObject-Entitäten in Java nicht schwer zu übersetzen ist, oder JavaScript, das auf dem Server ausgeführt werden soll, sodass sich wirklich nichts ändert.

Der erste und schnellste Ansatz ist mit MongoDB 2.6 und höher, wo Sie die neuen Set-Operationen erhalten:

var test = [ "t3", "t4", "t5" ];

db.collection.aggregate([
   { "$match": { "tags": {"$in": test } }},
   { "$project": {
       "tagMatch": {
           "$setIntersection": [
               "$tags",
               test
           ]
       },
       "sizeMatch": {
           "$size": {
               "$setIntersection": [
                   "$tags",
                   test
               ]
           }
       }
   }},
   { "$match": { "sizeMatch": { "$gte": 1 } } },
   { "$project": { "tagMatch": 1 } }
])

Die neuen Operatoren dort sind $setIntersection das macht die Hauptarbeit und auch der $size Operator, der die Array-Größe misst und bei der letzteren Filterung hilft. Dies endet als einfacher Vergleich von "Mengen", um die Elemente zu finden, die sich überschneiden.

Wenn Sie eine frühere Version von MongoDB haben, ist dies immer noch möglich, aber Sie benötigen ein paar weitere Stufen und dies kann die Leistung etwas beeinträchtigen, je nachdem, ob Sie große Arrays haben:

var test = [ "t3", "t4", "t5" ];

db.collection.aggregate([
   { "$match": { "tags": {"$in": test } }},
   { "$project": {
      "tags": 1,
      "match": { "$const": test }
   }},
   { "$unwind": "$tags" },
   { "$unwind": "$match" },
   { "$project": {
       "tags": 1,
       "matched": { "$eq": [ "$tags", "$match" ] }
   }},
   { "$match": { "matched": true }},
   { "$group": {
       "_id": "$_id",
       "tagMatch": { "$push": "$tags" },
       "count": { "$sum": 1 }
   }}
   { "$match": { "count": { "$gte": 1 } }},
   { "$project": { "tagMatch": 1 }}
])

Oder wenn all das zu kompliziert erscheint oder Ihre Arrays groß genug sind, um einen Leistungsunterschied zu machen, dann gibt es immer mapReduce :

var test = [ "t3", "t4", "t5" ];

db.collection.mapReduce(
    function () {
      var intersection = this.tags.filter(function(x){
          return ( test.indexOf( x ) != -1 );
      });
      if ( intersection.length > 0 ) 
          emit ( this._id, intersection );
   },
   function(){},
   {
       "query": { "tags": { "$in": test } },
       "scope": { "test": test },
       "output": { "inline": 1 }
   }
)

Beachten Sie, dass in allen Fällen der $in -Operator hilft Ihnen immer noch, die Ergebnisse zu reduzieren, auch wenn es nicht die vollständige Übereinstimmung ist. Das andere gemeinsame Element ist die Überprüfung der "Größe" des Schnittpunktergebnisses, um die Antwort zu reduzieren.

Alles ziemlich einfach zu programmieren, überzeugen Sie den Chef, zu MongoDB 2.6 oder höher zu wechseln, wenn Sie nicht bereits dort sind, um die besten Ergebnisse zu erzielen.