sql >> Database teknologi >  >> NoSQL >> MongoDB

MongoDb :Find fælles element fra to arrays i en forespørgsel

Der er et par tilgange til at gøre, hvad du vil, det afhænger bare af din version af MongoDB. Indsender bare shell-svarene. Indholdet er grundlæggende JSON-repræsentation, som ikke er svært at oversætte for DBObject-enheder i Java, eller JavaScript, der skal udføres på serveren, så det ændrer sig ikke.

Den første og hurtigste tilgang er med MongoDB 2.6 og nyere, hvor du får de nye sæt operationer:

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 nye operatører der er $setIntersection der udfører hovedarbejdet og også $ størrelse operator som måler array-størrelsen og hjælper til sidstnævnte filtrering. Dette ender som en grundlæggende sammenligning af "sæt" for at finde de elementer, der krydser hinanden.

Hvis du har en tidligere version af MongoDB, er dette stadig muligt, men du har brug for et par trin mere, og dette kan påvirke ydeevnen noget, afhængigt af om du har store arrays:

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 hvis alt det ser ud til at være involveret, eller dine arrays er store nok til at gøre en forskel i ydeevnen, så er der altid 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 }
   }
)

Bemærk, at i alle tilfælde $in operatør hjælper dig stadig med at reducere resultaterne, selvom det ikke er det fulde match. Det andet fælles element er at kontrollere "størrelsen" af skæringsresultatet for at reducere svaret.

Alt sammen ret nemt at kode. Overbevis chefen om at skifte til MongoDB 2.6 eller nyere, hvis du ikke allerede er der for at få de bedste resultater.




  1. Sådan gentager du objekter i Collection Meteor Mongo

  2. Redis, vil et emne (pub/sub) altid blive leveret til mindst én abonnent?

  3. Betinget gruppering med $ findes inde i $cond

  4. Hvordan gemmer man filer i MongoDB?