MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDb:Encontre o elemento comum de duas matrizes em uma consulta


Existem algumas abordagens para fazer o que você deseja, depende apenas da sua versão do MongoDB. Apenas enviando as respostas do shell. O conteúdo é basicamente uma representação JSON que não é difícil de traduzir para entidades DBObject em Java, ou JavaScript para ser executado no servidor para que realmente não mude.

A primeira e mais rápida abordagem é com o MongoDB 2.6 e superior, onde você obtém as novas operações de conjunto:
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 } }
])

Os novos operadores são $setIntersection que está fazendo o trabalho principal e também o $ tamanho operador que mede o tamanho do array e auxilia na filtragem deste último. Isso acaba sendo uma comparação básica de "conjuntos" para encontrar os itens que se cruzam.

Se você tiver uma versão anterior do MongoDB, isso ainda é possível, mas você precisa de mais alguns estágios e isso pode afetar um pouco o desempenho, dependendo se você tiver matrizes grandes:
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 se tudo isso parece envolvido ou seus arrays são grandes o suficiente para fazer uma diferença de desempenho, então sempre há 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 }
   }
)

Observe que, em todos os casos, o $in O operador ainda ajuda a reduzir os resultados, mesmo que não seja a correspondência completa. O outro elemento comum é verificar o "tamanho" do resultado da interseção para reduzir a resposta.

Tudo muito fácil de codificar, convença o chefe a mudar para o MongoDB 2.6 ou superior se você ainda não estiver lá para obter os melhores resultados.