【问题标题】:Matching all elements in an array in an array of arrays with $all in MongoDB用MongoDB中的$all匹配数组中数组中的所有元素
【发布时间】:2015-02-11 08:33:13
【问题描述】:

我有一份包含以下文件的文件:

{ "f" : [ [ 1, 2, 3], [4, 5, 6] ] } // should match because of [1, 2, 3]
{ "f" : [ [ 2, 1, 3], [4, 5, 6] ] } // should match because of [2, 1, 3]
{ "f" : [ [ 1, 2, 4], [4, 5, 6] ] } // should NOT match

在这个集合中,我想匹配文档,该文档在“f”字段的一个数组中包含一个包含 1、2 和 3 的数组。

到目前为止我已经尝试过:

db.mytest.find({ f: { $elemMatch: { $all: [1,2,3] } } } )

我希望这个查询能够工作,但我不明白为什么它不能。我没有匹配任何文件。

db.mytest.find({ f: { $elemMatch: { $elemMatch: { $all: [1,2,3] } } } })

这也行不通。

db.mytest.find({ f: { $all: [[1,2,3]] } })

这可行,但元素必须按准确顺序排列。当输入数组为 2、1、3 时,我也希望能够匹配。一种可能的解决方案必须是始终按升序存储元素并使用此查询。

db.mytest.find({ f: { $elemMatch: { $elemMatch: { $in: [1, 2, 3] } } } })

这可行,但它匹配包含 1、2 或 3 中任何一个的所有文档。我只想要在单个数组中恰好包含 1、2 和 3 的文档。

我要查找的查询是什么?

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    在嵌入数组的情况下,运算符似乎执行了完全匹配。不是最令人愉悦或最佳的解决方案(您需要使用集合中的记录对其进行测试),但一种方法是通过服务器端的聚合管道。

    • Project 每个文档都有一个额外的字段,表示“f”值。
    • unwind实际的“f”字段,这样我们就可以匹配单个数组了 元素。
    • match "f" 包含输入中所有值的文档 数组。
    • project 返回原始文档的临时字段。

    代码:

    db.mytest.aggregate([
    {$project:{"temp":"$f","f":1}},    // maintain a temporary variable for projection
    {$unwind:"$f"},                    // f:[1,2,3] f:[4,5,6] become separate records.
    {$match:{"f":{$all:[1,2,3]}}},     // use $all to match all the elements. 
    {$project:{"f":"$temp"}}           // project the temporary variable.
    ])
    

    【讨论】:

      【解决方案2】:

      您正在查找f 包含[1, 2, 3] 的文档。试试db.mytest.find({f: {$in: [[1, 2, 3]]}})

      不幸的是,找到所有可能排列的最简单方法是在您的程序中构建它们(如果您使用 Python,itertools.permutations 将为您完成)并将您的 $in 查询更改为 [[1, 2, 3], [2, 1, 3], ...] .太烂了。

      【讨论】:

      • 这仅在我将数字按正确顺序排列时才有效。 db.mytest.find({f: {$in: [[2, 1, 3]]}}) 不起作用。
      • 我不是在寻找 f 包含 [1,2,3] 的文档。我正在寻找文档,其中 f 中的一个数组以任意顺序包含 1、2 和 3。这就是这个查询不起作用的原因。
      • @Disposer 请您再检查一次好吗?我的 mongo 版本是 2.6.4,它与 document { "f" : [ [ 1, 2, 3 ], [ 4, 5, 6 ]]} 不匹配。我也看不出它是如何工作的,因为 $in 试图完全匹配至少一个字段。
      【解决方案3】:

      如何生成数组的所有排列并在查询中使用?像这样:

      db.mytest.find({$or : [{f: {$all : [[1,2,3]] }}, {f: {$all : [[2,1,3]]}}, {f: {$all: [[3,1,2]]}}]})
      

      也许这不是有效的方法。

      【讨论】:

      • 这会占用太多空间。取而代之的是,我总是可以按升序将元素存储在数组中,但如果有的话,我正在为我当前的集合寻找解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-19
      • 2013-03-03
      • 2023-03-04
      • 1970-01-01
      • 2016-03-26
      • 1970-01-01
      相关资源
      最近更新 更多