如何使用mongodb更新包含在父对象数组中的对象的属性?

14ifxucb  于 2023-01-16  发布在  Go
关注(0)|答案(5)|浏览(129)

我使用MongoDB作为我的数据库。我有一个数据:

{
   _id : '123'
   friends: [
     {name: 'allen', emails: [{email: '11111', using: 'true'}]}
   ]
 }

现在,我想修改用户的朋友的电子邮件的电子邮件,其_id是'123'我这样写:

db.users.update ({_id: '123'}, {$set: {"friends.0.emails.$.email" : '2222'} })

这很简单,但是,当电子邮件数组有两个或更多数据时,这是错误的。因此,我的问题是:如何修改嵌套字段中的数据---只有两个或多个嵌套数组?谢谢。

bwleehnv

bwleehnv1#

您需要对数组使用点标记法。
也就是说,应该用要更新的元素的从零开始的索引替换$
例如:

db.users.update ({_id: '123'}, { '$set': {"friends.0.emails.0.email" : '2222'} });

将更新所述第一朋友的所述第一电子邮件,以及

db.users.update ({_id: '123'}, { '$set': {"friends.0.emails.1.email" : '2222'} })

将更新第一朋友的第二电子邮件。

sczxawaw

sczxawaw2#

更新多级数组的一种灵活方法是使用arrayFilters,它允许查询索引并将索引分配给标识符。

db.collection.update(
   { <query selector> },
   { <update operator>: { "array.$[<identifier>].field" : value } },
   { arrayFilters: [ { <identifier>: <condition> } } ] }
)

下面是您提供的示例,外加一个新朋友的两封电子邮件:

{
   _id : '123'
   friends: [
     {name: 'allen', emails: [
        {email: '11111', using: 'true'}
     ]},
     {name: 'lucy' , emails: [
        {email: 'lucy@work.com', using:'true'}, 
        {email:'lucyGucy@zmail.com', using : 'false'}
     ]}
   ]
 }

假设lucyGucy@zmail.com被更新为lucy.is.gucy@zmail.com,我们可以在数组过滤器中使用 nameemail 字段来标识要更新的索引。

db.users.update({_id:123}, {$set:{
    "friends.$[updateFriend].emails.$[updateEmail].email" : "lucy.is.gucy@zmail.com"
}}, {
    "arrayFilters": [
      {"updateFriend.name" : "lucy"},
      {"updateEmail.email" : "lucyGucy@zmail.com"}
    ]
})

通过这种方式,更新对特定的数组顺序不敏感。上面的示例使用了两个标识符 updateFriendupdateEmail,这两个标识符将匹配(对于应用它们的数组)任何满足数组过滤条件的元素。如文档中所述:
必须以小写字母开始,并且只能包含字母数字字符。
此外,虽然电子邮件可能是唯一的,我会建议包括一个唯一的id对所有子文档,使arrayfilter可以是准确的。

rsaldnfx

rsaldnfx3#

使用Mongoose的溶液:

Users.findById("123", function(err, user) {

      var friends = user.friends;
        for ( i=0; i < friends.length; i++ ) {
          if (friends[i].name == 'allen') {
            friends[i].email = '2222';

            user.save(function(err) {
              if (err) throw err;
              console.log("email updated");
            });
          } else {
            console.log("no friends named allen");
          }
        }

    }
ygya80vv

ygya80vv4#

在一个多层次的arry中更新一些东西真的是很麻烦,我的做法是:替换深层次的arry。

db.user.findOne({_id:'123'},{friends:1}).lean().exec(function(err,user){
   var whichArrayToUpdate;
   for (var ii = 0; ii < user.friends.length; ii++) {
        for (var jj = 0; i < user.friends[ii].emails; jj++) {
            if(user.friends[ii].emails[jj].email == '1111' ){// update it below

                user.friends[ii].emails[jj].email == 'what ever you want to set to.';

                whichArrayToReplace = user.friends[ii].emails;
                break;
            }
        };
   };

   db.user.update({'friends.name':'allen'},{$set{'friends.$.email': whichArrayToReplace} })
})

但是,为什么不使用保存()方法呢?save()将替换你的整个文档,如果你的文档很小,那没关系,但是如果你的文档很大,最好只替换你文档的一部分.
或者循环,使用顶层数组和第二层数组(ii和jj)的位置来更新。
我的建议是:当你设计模式时,不要把数组放在另一个数组中,除非你不想对那个数组做任何更新。

v1uwarro

v1uwarro5#

我有一个类似的情况,我有主要类别,如:

{
    "service": {
        "isReviewed": false,
        "_id": "5ea36b27d7ae560845afb88d",
        "mainCategory": "message ",
        "SubCategory": [
            {
                "priceChanged": true,
                "_id": "5ea36b27d7ae560845afb88e",
                "subCatPrice": "26",
                "subCatName": "mustach trimming"
            }
        ],
        "shopName": "paddy the barber",
        "user": "5ea1fd5b69512dc72ad2f48c",
        "date_created": "2020-04-24T22:41:43.368Z",
        "__v": 5
    }
}

现在,它花了一段时间弄清楚如何更新子文档的一部分。因为子文档存储为对象。
所以All id,首先我检查doc通过put/:id时的_id,然后,我根据req.user检查doc的所有者。
如果一切正常,我循环遍历数组,然后生成一个新的对象。然后,我所做的就是检查每个req.body的价格或名称,如果有新的价格,我就更新对象中的价格值。如果有新的值,那么对象保持不变。
然后我所说的service.SubCategory = newObject并存储数据。
它工作正常,但是,我遇到了subdoc_id更新的问题,所以我通过将旧值保留为它的值来修复它。
现在,在性能和优化方面,我不完全确定这是否是正确的方式,但它的工作,如果他们更好,我愿意改变。
下面是代码:

const newObject = {
      subCatPrice: "",
      subCatName: "",
      _id: "",
      priceChanged: false
    };

    let oldDetails = service.SubCategory;
    for (const old of oldDetails) {
      newObject.subCatPrice = old.subCatPrice;
      newObject.subCatName = old.subCatName;
      newObject._id = old._id;
    }

    price ? (newObject.subCatPrice = price ) && (newObject.priceChanged = true)  : newObject.subCatPrice;
    name ? (newObject.subCatName = name) : newObject.subCatName;

    (service.SubCategory = newObject), await service.save();

老实说,我使用了状态的react思想,我只是得到对象的一个副本并保存它,然后对我想更新的部分应用更新。
同样,在干净的代码和所有这些东西方面,我不确定这是否是正确的方法,但我也是一个编程的学生,我也想学习。
希望这能帮助到一些人

相关问题