【问题标题】:Find MongoDB object using value of another field使用另一个字段的值查找 MongoDB 对象
【发布时间】:2016-04-16 07:00:14
【问题描述】:

我最近发现很难找到存储在文档中的对象,其键位于同一文档的另一个字段中。

{
    list : {
        "red" : 397n8,
        "blue" : j3847,
        "pink" : 8nc48,
        "green" : 983c4,
    },
    result : [
                { "id" : 397n8, value : "anger" },
                { "id" : j3847, value : "water" },
                { "id" : 8nc48, value : "girl" },
                { "id" : 983c4, value : "evil" }
             ]
    }
}

我正在尝试获取 id 为“j3847”且值为“water”的“blue”的值。

db.docs.find( { result.id : list.blue }, { result.value : 1 } );

# list.blue would return water
# list.pink would return girl
# list.green would return evil

我尝试了很多事情,甚至发现了一篇关于如何使用同一文档中的值更新值的好文章。:Update MongoDB field using value of another field 我自己基于;没有成功...:/

如何使用另一个字段的值找到 MongoDB 对象?

【问题讨论】:

    标签: mongodb mongoose mongodb-query nosql


    【解决方案1】:

    一种方法是使用$where 运算符,但不推荐使用它,因为无论其他条件可能使用索引选择,它都会调用完整的集合扫描,并且还会在每个结果文档上调用 JavaScript 解释器,这将比本机代码慢得多。

    话虽如此,请使用替代的.aggregate() 方法进行此类比较,这绝对是更好的选择:

    db.docs.aggregate([
        { "$unwind": "$result" },
        {
            "$project": {
                "result": 1,
                "same": { "$eq": [ "$list.blue", "$result.id" ] }
            }
        },
        { "$match": { "same": true } },
        { 
            "$project": {
                "_id": 0,
                "value": "$result.value"
            }
        }
    ])
    

    当 $unwind 运算符应用于result 数组字段时,它将为应用展开的结果字段的每个元素生成一条新记录。它基本上将数据展平,然后在随后的 $project 步骤中检查数组的每个成员以比较两个字段是否相同。

    样本输出

    {
        "result" : [ 
            {
                "value" : "water"
            }        
        ],
        "ok" : 1
    }
    

    另一种方法是在单个 $project 步骤中使用 $map 和 $setDifference 运算符,您可以避免使用 $unwind 在非常大的集合上可能代价高昂,并且在大多数情况下会导致 16MB BSON 限制:

    db.docs.aggregate([
        {
            "$project": {
                "result": { 
                    "$setDifference": [
                        { 
                            "$map": {
                                "input": "$result",
                                "as": "r",
                                "in": { 
                                    "$cond": [
                                        { "$eq": [ "$$r.id", "$list.blue" ] },
                                        "$$r",
                                        false
                                    ]
                                }
                            }
                        },
                        [false]
                    ]
                }
            }
        }
    ])
    

    样本输出

    {
        "result" : [ 
            {
                "_id" : ObjectId("569412e5a51a6656962af1c7"),
                "result" : [ 
                    {
                        "id" : "j3847",
                        "value" : "water"
                    }
                ]
            }
        ],
        "ok" : 1
    }
    

    【讨论】:

    • 您的查询是遍历整个文档集合,还是我们可以使用文档 _id 指定要“聚合”的文档?
    • 如果您想通过_id 或任何其他键过滤进入聚合管道的文档,您可以使用$match 管道运算符。这类似于 MongoDB Collection 的 find() 方法和 SQL 的 WHERE 子句。基本上,这会过滤传递给下一个操作员的数据。管道中可以有多个 $match 运算符。
    【解决方案2】:

    您可以使用 mongo 聚合中的 $filter 运算符来实现。它返回一个仅包含符合条件的元素的数组:

    db.docs.aggregate([
      {  
        $project: {
          result: {
            $filter: {
              input: "$result", 
              as:"item", 
              cond: { $eq: ["$list.blue", "$$item.id"]}
            }
          }
        }
      }
    ])
    

    此查询的输出如下所示:

    { 
      "_id" : ObjectId("569415c8299692ceedf86573"), 
      "result" : [ { "id" : "j3847", "value" : "water" } ] 
    }
    

    【讨论】:

    • 除了符合条件的值之外,是否可以返回其他值?
    • @samland 是的,您可以使用以下语法向projection 添加其他字段:字段:1。或者您可以使用$$ROOT 将整个文档投影到字段中。在投影中它看起来像这样:document: 'ROOT'
    猜你喜欢
    • 1970-01-01
    • 2019-05-18
    • 2011-04-27
    相关资源
    最近更新 更多