MongoDb:从查询中的两个数组中查找公共元素



假设我们在数据库中有以下结构的记录:

{
  "_id": 1234,
  "tags" : [ "t1", "t2", "t3" ]
}

现在,我想检查数据库是否包含在数组tagsArray which is [ "t3", "t4", "t5" ]

中指定的任何标签的记录

我知道$in操作符,但我不仅想知道数据库中的任何记录是否有tagsArray中指定的任何标签,我还想知道数据库中记录的哪个标签与tagsArray中指定的任何标签匹配。(即t3在上述记录的情况下)

也就是说,我想比较两个数组(一个是记录,另一个是我给出的)并找出公共元素。

我需要在查询中有这个表达式以及许多表达式,因此像$,$ eleatch等投影运算符不会有太大用处。(或者有没有一种方法可以使用它而不必遍历所有记录?)

我认为我可以使用$where操作符,但我不认为这是最好的方法。如何解决这个问题?

有几种方法可以做你想做的事情,这取决于你的MongoDB版本。只是提交shell响应。内容基本上是JSON表示,不难翻译成Java中的DBObject实体,或者在服务器上执行的JavaScript,所以这真的不会改变。

第一个也是最快的方法是MongoDB 2.6和更高版本,在那里你可以获得新的set操作:
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 } }
])

新的运算符有 $setIntersection ,它是做主要工作的,还有 $size 运算符,它测量数组的大小并帮助后期的过滤。为了找到相交的项,这最终成为"集合"的基本比较。

如果你有一个早期版本的MongoDB,那么这仍然是可能的,但你需要更多的阶段,这可能会影响性能,如果你有大数组:

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

如果所有这些都涉及到,或者你的数组足够大,可以产生性能差异,那么总是有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 }
   }
)
请注意,在所有情况下, $in 操作符仍然可以帮助您减少结果,即使它不是完全匹配。另一个常见元素是检查相交结果的"大小",以减少响应。

所有很容易编码,说服老板切换到MongoDB 2.6或更高版本,如果你还没有最好的结果。

相关内容

  • 没有找到相关文章