sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDb :Hitta gemensamma element från två arrayer i en fråga

Det finns några sätt att göra vad du vill, det beror bara på din version av MongoDB. Skickar bara in skalsvaren. Innehållet är i grunden JSON-representation som inte är svårt att översätta för DBObject-entiteter i Java, eller JavaScript som ska köras på servern så att det verkligen inte förändras.

Det första och snabbaste tillvägagångssättet är med MongoDB 2.6 och senare där du får de nya setoperationerna:

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

De nya operatörerna där är $setIntersection som gör huvudarbetet och även $ storlek operator som mäter arraystorleken och hjälper till med den senare filtreringen. Detta slutar som en grundläggande jämförelse av "uppsättningar" för att hitta objekten som skär varandra.

Om du har en tidigare version av MongoDB är detta fortfarande möjligt, men du behöver några fler steg och detta kan påverka prestandan något beroende på om du har stora arrayer:

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

Eller om allt detta verkar vara inblandat eller om dina arrayer är tillräckligt stora för att göra en prestandaskillnad så finns det alltid 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 }
   }
)

Observera att i alla fall $in operatören hjälper dig fortfarande att minska resultaten även om det inte är den fullständiga matchningen. Det andra vanliga elementet är att kontrollera "storleken" på korsningsresultatet för att minska svaret.

Allt ganska lätt att koda, övertyga chefen att byta till MongoDB 2.6 eller senare om du inte redan är där för bästa resultat.




  1. C# MongoDB:Hur mappar man ett domänobjekt korrekt?

  2. Geospatial $nära inom aktuellt dokumentfältvärde

  3. Kontrollera objektets existens i mongo med gopkg.in/mgo.v2

  4. Timeout-fel vid anslutning till CosmosDB med MongoDB API