【问题标题】:Query and Update Child Documents without knowing keys在不知道密钥的情况下查询和更新子文档
【发布时间】:2017-09-27 07:19:31
【问题描述】:

我有一个包含以下格式的文档的集合

{
    name: "A",
    details : {
        matchA: {
            comment: "Hello",
            score: 5
        },
        matchI: {
            score: 10
        },
        lastMatch:{
        score: 5
        }
    }
},
{
    name: "B",
    details : {
        match2: {
            score: 5
        },
        match7: {
            score: 10
        },
        firstMatch:{
        score: 5
        }
    }
}

我不立即知道作为详细信息子项的键的名称,它们不遵循已知格式,可能有不同的数量等。

我想编写一个查询,该查询将以这样一种方式更新子文档,即任何分数低于 5 的子文档都会添加一个新字段(比如 lowScore: true)。

我环顾四周,发现了 $ 和 $elemMatch,但它们只适用于数组。子文档是否有等价物?有没有使用聚合管道的方法?

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    我认为你不能使用普通的update() 来做到这一点。有一种方法通过聚合框架,但是,它本身不能更改任何持久数据。因此,您将需要遍历结果并单独更新您的文档,例如这里:Aggregation with update in mongoDB

    这是将数据转换为后续更新所需的查询:

    collection.aggregate({
        $addFields: {
            "details": {
                $objectToArray: "$details" // transform "details" into uniform array of key-value pairs
            }
        }
    }, {
        $unwind: "$details" // flatten the array created above
    }, {
        $match: {
            "details.v.score": {
                $lt: 10 // filter out anything that's not relevant to us
                // (please note that I used some other filter than the one you wanted "score less than 5" to get some results using your sample data
            },
            "details.v.lowScore": { // this filter is not really required but it seems to make sense to check for the presence of the field that you want to create in case you run the query repeatedly
                $exists: false
            }
        }
    }, {
        $project: {
            "fieldsToUpdate": "$details.k" // ...by populating the "details" array again
        }
    })
    

    运行此查询返回:

    /* 1 */
    {
        "_id" : ObjectId("59cc0b6afab2f8c9e1404641"),
        "fieldsToUpdate" : "matchA"
    }
    
    /* 2 */
    {
        "_id" : ObjectId("59cc0b6afab2f8c9e1404641"),
        "fieldsToUpdate" : "lastMatch"
    }
    
    /* 3 */
    {
        "_id" : ObjectId("59cc0b6afab2f8c9e1404643"),
        "fieldsToUpdate" : "match2"
    }
    
    /* 4 */
    {
        "_id" : ObjectId("59cc0b6afab2f8c9e1404643"),
        "fieldsToUpdate" : "firstMatch"
    }
    

    然后您可以使用上面链接答案中描述的光标$set 您的新字段"lowScore"

    【讨论】:

      猜你喜欢
      • 2019-07-08
      • 2021-11-14
      • 1970-01-01
      • 2020-10-18
      • 2013-08-19
      • 2021-12-20
      • 1970-01-01
      • 2018-01-18
      • 1970-01-01
      相关资源
      最近更新 更多