为了账号安全,请及时绑定邮箱和手机立即绑定

Mongodb更新深层嵌套的子文档

/ 猿问

Mongodb更新深层嵌套的子文档

蝴蝶不菲 2019-09-21 13:57:56

我有一个深层嵌套的文档结构,如下所示:


{id: 1, 

 forecasts: [ { 

             forecast_id: 123, 

             name: "Forecast 1", 

             levels: [ 

                { level: "proven", 

                  configs: [

                            { 

                              config: "Custom 1",

                              variables: [{ x: 1, y:2, z:3}]

                            }, 

                            { 

                              config: "Custom 2",

                              variables: [{ x: 10, y:20, z:30}]

                            }, 

                    ]

                }, 

                { level: "likely", 

                  configs: [

                            { 

                              config: "Custom 1",

                              variables: [{ x: 1, y:2, z:3}]

                            }, 

                            { 

                              config: "Custom 2",

                              variables: [{ x: 10, y:20, z:30}]

                            }, 

                    ]

                }

            ]

        }, 

    ]


}

我正在尝试更新集合以插入新的配置,如下所示:


newdata =  {

  config: "Custom 1", 

  variables: [{ x: 111, y:2222, z:3333}]

}

我正在mongo中尝试这样的事情(在Python中):


db.myCollection.update({"id": 1, 

                        "forecasts.forecast-id": 123, 

                        "forecasts.levels.level": "proven", 

                        "forecasts.levels.configs.config": "Custom 1"

                         },

                         {"$set": {"forecasts.$.levels.$.configs.$": newData}}

                      )

我收到“无法在没有包含数组的相应查询字段的情况下应用位置运算符”错误。在mongo中执行此操作的正确方法是什么?这是mongo v2.4.1。


查看完整描述

3 回答

?
幕布斯5086720

不幸的是,$每个键不能多次使用运算符,因此其余部分必须使用数字值。如:


db.myCollection.update({

    "id": 1, 

    "forecasts.forecast-id": 123, 

    "forecasts.levels.level": "proven", 

    "forecasts.levels.configs.config": "Custom 1"

  },

  {"$set": {"forecasts.$.levels.0.configs.0": newData}}

)

MongoDB对更新嵌套数组的支持很差。因此,如果您需要经常更新数据,则最好避免使用它们,并考虑改用多个集合。


一种可能:创建forecasts自己的集合,并假设您具有一组固定的level值,则创建level一个对象而不是一个数组:


{

  _id: 123,

  parentId: 1,

  name: "Forecast 1", 

  levels: {

    proven: { 

      configs: [

        { 

          config: "Custom 1",

          variables: [{ x: 1, y:2, z:3}]

        }, 

        { 

          config: "Custom 2",

          variables: [{ x: 10, y:20, z:30}]

        }, 

      ]

    },

    likely: {

      configs: [

        { 

          config: "Custom 1",

          variables: [{ x: 1, y:2, z:3}]

        }, 

        { 

          config: "Custom 2",

          variables: [{ x: 10, y:20, z:30}]

        }, 

      ]

    }

  }

}

然后,您可以使用以下命令进行更新:


db.myCollection.update({

    _id: 123,

    'levels.proven.configs.config': 'Custom 1'

  },

  { $set: { 'levels.proven.configs.$': newData }}

)


查看完整回答
反对 回复 2019-09-21
?
函数式编程

设法用猫鼬解决它:


您只需要知道链中所有子文档的“ _id”(猫鼬会为每个子文档自动创建“ _id”)。


例如 -


  SchemaName.findById(_id, function (e, data) {

      if (e) console.log(e);

      data.sub1.id(_id1).sub2.id(_id2).field = req.body.something;


      // or if you want to change more then one field -

      //=> var t = data.sub1.id(_id1).sub2.id(_id2);

      //=> t.field = req.body.something;


      data.save();

  });

猫鼬文档中有关子文档_id方法的更多信息。


说明:_id用于SchemaName,_id1用于sub1,_id2用于sub2-您可以像这样保持链接。


*您不必使用findById方法,但是对我来说,这似乎是最方便的,因为您仍然需要了解其余的'_id'。


查看完整回答
反对 回复 2019-09-21
?
森栏

MongoDB 在3.5.2版和更高版本中引入了ArrayFilters来解决此问题。


3.6版的新功能。


从MongoDB 3.6开始,在更新数组字段时,您可以指定arrayFilters确定要更新的数组元素。


[ https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-an-array-update-operations][1]


假设Schema设计如下:


var ProfileSchema = new Schema({

    name: String,

    albums: [{

        tour_name: String,

        images: [{

            title: String,

            image: String

        }]

    }]

});

创建的文档如下所示:


{

   "_id": "1",

   "albums": [{

            "images": [

               {

                  "title": "t1",

                  "url": "url1"

               },

               {

                  "title": "t2",

                  "url": "url2"

               }

            ],

            "tour_name": "london-trip"

         },

         {

            "images": [.........]: 

         }]

}

说我要更新图像的“ URL”。鉴于-  "document id", "tour_name" and "title"


为此,更新查询:


Profiles.update({_id : req.body.id},

    {

        $set: {


            'albums.$[i].images.$[j].title': req.body.new_name

        }

    },

    {

        arrayFilters: [

            {

                "i.tour_name": req.body.tour_name, "j.image": req.body.new_name   // tour_name -  current tour name,  new_name - new tour name 

            }]

    })

    .then(function (resp) {

        console.log(resp)

        res.json({status: 'success', resp});

    }).catch(function (err) {

    console.log(err);

    res.status(500).json('Failed');

})


查看完整回答
反对 回复 2019-09-21

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信