MongoDB查找精确数组匹配,但顺序并不重要

时间:2015-04-21 13:45:50

标签: arrays mongodb mongodb-query

我正在查询找到精确的数组匹配并成功检索它但是当我尝试找出具有不同顺序值的确切数组时,它就会失败。

Example

db.coll.insert({"user":"harsh","hobbies":["1","2","3"]})
db.coll.insert({"user":"kaushik","hobbies":["1","2"]})
db.coll.find({"hobbies":["1","2"]})

第二个文档成功检索

db.coll.find({"hobbies":["2","1"]})

什么都不显示

请帮忙

6 个答案:

答案 0 :(得分:29)

currently accepted answer不能确保数组完全匹配,只是大小相同,并且数组与查询数组共享至少一个项目。

例如,查询

db.coll.find({ "hobbies": { "$size" : 2, "$in": [ "2", "1", "5", "hamburger" ] }  });
在这种情况下,

仍会返回用户kaushik。

完全匹配需要做的是将$size$all合并,如下所示:

db.coll.find({ "hobbies": { "$size" : 2, "$all": [ "2", "1" ] }  });

但请注意,这可能是一项非常昂贵的操作,具体取决于您的数据量和结构。 由于MongoDB保持插入数组的顺序稳定,因此在插入数据库时​​确保数组处于排序顺序可能会更好,因此在查询时可能依赖于静态顺序。

答案 1 :(得分:11)

为了匹配数组字段,Mongo提供了$eq运算符,它可以在数组上运行,也可以像值一样运行。

db.collection.find({ "hobbies": {$eq: [ "singing", "Music" ] }});

同样$eq会检查您指定元素的顺序。

如果您使用以下查询:

db.coll.find({ "hobbies": { "$size" : 2, "$all": [ "2", "1" ] }  });

然后不会返回完全匹配。假设你查询:

db.coll.find({ "hobbies": { "$size" : 2, "$all": [ "2", "2" ] }  });

此查询将返回具有元素2且大小为2的所有文档(例如,它还将返回具有hobies :[2,1]的文档。)

答案 2 :(得分:0)

此查询将找到任意顺序的精确数组。

let query = {$or: [
{hobbies:{$eq:["1","2"]}},
{hobbies:{$eq:["2","1"]}}
]};

db.coll.find(query)

答案 3 :(得分:0)

使用 $ all ,我们可以实现这一目标。  查询: {cast:{$ all:[“ James J. Corbett”,“ George Bickel”]}}

输出:演员:[“乔治·比克尔”,“艾玛·卡鲁斯”,“乔治·科汉”,“詹姆斯·科贝特”]

答案 4 :(得分:0)

使用aggregate,这是我变得精通和更快的方式:

 db.collection.aggregate([
 {$unwind: "$array"},
 
  {
        
    $match: {
      
      "array.field" : "value"
      
    }
  },

然后您可以再次展开以使其成为平面阵列,然后对其进行分组。

答案 5 :(得分:0)

这个问题已经很老了,但是我被ping通了,因为另一个答案表明接受的答案不足以包含重复值的数组,所以让我们解决这个问题。

由于我们在查询功能上有一个基本的基本限制,因此我们需要避免这些容易出错且容易出错的数组交集。检查两个数组是否包含一组相同的值而不对每个值进行显式计数的最好方法是对我们要比较的两个数组进行排序,然后比较这些数组的排序版本。据我所知,由于MongoDB不支持数组排序,因此我们将需要依靠聚合来模仿我们想要的行为:

// Note: make sure the target_hobbies array is sorted!
var target_hobbies = [1, 2];

db.coll.aggregate([
  { // Limits the initial pipeline size to only possible candidates.
    $match: {
      hobbies: {
        $size: target_hobbies.length,
        $all: target_hobbies
      }
    }
  },
  { // Split the hobbies array into individual array elements.
    $unwind: "$hobbies"
  },
  { // Sort the elements into ascending order (do 'hobbies: -1' for descending).
    $sort: {
      _id: 1,
      hobbies: 1
    }
  },
  { // Insert all of the elements back into their respective arrays.
    $group: {
      _id: "$_id",
      __MY_ROOT: { $first: "$$ROOT" }, // Aids in preserving the other fields.
      hobbies: {
        $push: "$hobbies"
      }
    }
  },
  { // Replaces the root document in the pipeline with the original stored in __MY_ROOT, with the sorted hobbies array applied on top of it.
    // Not strictly necessary, but helpful to have available if desired and much easier than a bunch of 'fieldName: {$first: "$fieldName"}' entries in our $group operation.
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          "$__MY_ROOT",
          {
            hobbies: "$hobbies"
          }
        ]
      }
    }
  }
  { // Now that the pipeline contains documents with hobbies arrays in ascending sort order, we can simply perform an exact match using the sorted target_hobbies.
    $match: {
      hobbies: target_hobbies
    }
  }
]);

我不能代表此查询的性能,并且如果初始候选文档过多,很可能导致管道过大。如果您使用的是大型数据集,请再次按照当前接受的答案状态进行操作,并按排序顺序插入数组元素。这样,您可以执行静态数组匹配,这将更加高效,因为可以对其进行正确索引,并且不受聚合框架的管道大小限制。但这是权宜之计,应该确保更高的准确性。