首页 > 解决方案 > 构建动态 MongoDB 查询以更新 dict 中的嵌套值

问题描述

考虑这样的对象:

{
    "_id" : ObjectId("5b4dbf3541e5ae6de394cc99"),
    "active" : true,
    "email" : "admin@something.eu",
    "password" : "$2b$12$5qqD3ZulKI7S6j.Wx513POpCNWRMppE.vY4.3EIZedm109VUPqXoi",
    "badges" : {
        "cnc" : {
            "lvl" : "0"
        },
        "laser" : {
            "lvl" : "0"
        },
        "impression3d" : {
            "lvl" : "0"
        },
        "maker" : {
            "lvl" : "0"
        },
        "electronique" : {
            "lvl" : "0"
        },
        "badge" : {
            "lvl" : 1
        }
    },
    "roles" : [ 
        ObjectId("5b4dbf3541e5ae6de394cc97")
    ]
}

我需要将lvl值更改为 0 到 5 之间的任何值,不一定是不规则的增量。为此,父对象名称由变量传递,因此我正在尝试为要更改的徽章 lvl 构建动态查询。

目前我的 Flask 路线的结尾如下所示:

badge = quiz['badge']
C_user = current_user.get_id()
update = bdd.user.update({"_id": C_user, "badges": { '$elemMatch': {badges : badge}}}, {"$set": { "badges.$.lvl": 3 }}, upsert = True)

但是对于这种查询,我收到一条错误消息:

pymongo.errors.WriteError: The positional operator did not find the match needed from the query.

我是否完全错误地认为我需要使用 $elemMatch 运算符?有没有办法动态定位不同的徽章来增加内部的等级?

谢谢!

注意:我第一次尝试使用 MongoEngine,但似乎无法深入研究。

标签: mongodbflaskpymongo

解决方案


你不能这样做,徽章是一个文档,而不是一个数组。尝试

 ...
 {"$set": { "badges.badge.lvl": 3 }} 
 ...

但是您必须为每个徽章字段明确执行此操作。使用查询的方法是更新您的方案,例如

...
"badges" : [
    {name:"cnc", 
        "lvl" : "0"
    },
    {"name":"laser",
        "lvl" : "0"},
    ...
    ]
    ...

编辑:随着您的计划的一些更新,这是实现目标的一种方法:

新数据架构:

{ 
    "_id" : ObjectId("5b4dbf3541e5ae6de394cc99"), 
    "active" : true, 
    "email" : "admin@something.eu", 
    "password" : "$2b$12$5qqD3ZulKI7S6j.Wx513POpCNWRMppE.vY4.3EIZedm109VUPqXoi", 
    "badges" : [
        {
            "name" : "cnc", 
            "lvl" : "0"
        }, 
        {
            "name" : "laser", 
            "lvl" : "5"
        }, 
        {
            "name" : "impression3d", 
            "lvl" : "0"
        }, 
        {
            "name" : "maker", 
            "lvl" : "0"
        }, 
        {
            "name" : "electronique", 
            "lvl" : "0"
        }, 
        {
            "name" : "badge", 
            "lvl" : 1
        }
    ], 
    "roles" : [
        ObjectId("5b4dbf3541e5ae6de394cc97")
    ]
}

这里有一个更新查询:

db['02'].update(
   {_id: ObjectId("5b4dbf3541e5ae6de394cc99")}, // <= here you filter your documents
   { $set: { "badges.$[elem].lvl": "10" } },  // <= use of positionnal operator with identifier, needed for arrayFilters. elem is arbitraty
   { arrayFilters: [ { "elem.name": "laser" } ], // <= update only elements in array that match arrayFilters. 
     upsert: true }
)

推荐阅读