MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDb :Trouver l'élément commun de deux tableaux dans une requête

Il existe plusieurs approches pour faire ce que vous voulez, cela dépend simplement de votre version de MongoDB. Il suffit de soumettre les réponses du shell. Le contenu est essentiellement une représentation JSON qui n'est pas difficile à traduire pour les entités DBObject en Java, ou JavaScript à exécuter sur le serveur afin que cela ne change vraiment pas.

La première et la plus rapide approche est avec MongoDB 2.6 et supérieur où vous obtenez les nouvelles opérations d'ensemble :

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

Les nouveaux opérateurs sont $setIntersection qui fait le travail principal et aussi le $size opérateur qui mesure la taille du tableau et aide à ce dernier filtrage. Cela se termine par une comparaison de base des "ensembles" afin de trouver les éléments qui se croisent.

Si vous avez une version antérieure de MongoDB, cela est toujours possible, mais vous avez besoin de quelques étapes supplémentaires et cela peut affecter quelque peu les performances selon si vous avez de grands tableaux :

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

Ou si tout cela semble impliqué ou si vos tableaux sont suffisamment grands pour faire une différence de performances, il y a toujours 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 }
   }
)

Notez que dans tous les cas, le $in L'opérateur vous aide toujours à réduire les résultats même s'il ne s'agit pas de la correspondance complète. L'autre élément commun est de vérifier la "taille" du résultat de l'intersection pour réduire la réponse.

Tout est assez facile à coder, convainquez le patron de passer à MongoDB 2.6 ou supérieur si vous n'êtes pas déjà là pour obtenir les meilleurs résultats.