sql >> Database >  >> NoSQL >> MongoDB

MongoDb:Vind gemeenschappelijk element uit twee arrays binnen een query

Er zijn een paar benaderingen om te doen wat je wilt, het hangt gewoon af van je versie van MongoDB. Gewoon de shell-reacties indienen. De inhoud is in feite JSON-representatie die niet moeilijk te vertalen is voor DBObject-entiteiten in Java, of JavaScript om op de server te worden uitgevoerd, dus dat verandert echt niet.

De eerste en snelste benadering is met MongoDB 2.6 en hoger, waar u de nieuwe setbewerkingen krijgt:

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 nieuwe operators daar zijn $setIntersection dat doet het hoofdwerk en ook de $size operator die de arraygrootte meet en helpt bij de laatste filtering. Dit wordt een basisvergelijking van "sets" om de items te vinden die elkaar kruisen.

Als je een eerdere versie van MongoDB hebt, is dit nog steeds mogelijk, maar je hebt nog een paar fasen nodig en dit kan de prestaties enigszins beïnvloeden, afhankelijk van of je grote arrays hebt:

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

Of als dat allemaal te maken lijkt te hebben of als uw arrays groot genoeg zijn om een ​​prestatieverschil te maken, dan is er altijd nog 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 }
   }
)

Merk op dat in alle gevallen de $in operator helpt u nog steeds om de resultaten te verminderen, ook al is het niet de volledige overeenkomst. Het andere gemeenschappelijke element is het controleren van de "grootte" van het resultaat van de kruising om de respons te verminderen.

Allemaal vrij eenvoudig te coderen, overtuig de baas om over te schakelen naar MongoDB 2.6 of hoger als je er nog niet bent voor de beste resultaten.




  1. Hoe kan ik reguliere expressies gebruiken met Doctrine's Mongodb ODM?

  2. mangoest aggregaat met $exists in $cond

  3. Een elegantere manier om met filterwaarden om te gaan in de Angular-app

  4. MongoDB C# Aggregatie - afwikkelen -> groupBy