mongo更新数组字段_mongo更新文档中的数组

测试数据如下,memberList里存放的是每个成员member的内嵌文档

{

"_id" : ObjectId("5eb17213bcab265fc1959eb7"),

"memberList" : [

{

"uid" : "1",

"nickName" : "昵称1",

"locInfo" : {

"lon" : 116.47274,

"lat" : 39.9932969444444

}

},

{

"uid" : "2",

"nickName" : ""昵称2",

"locInfo" : {

"lon" : 116.47274,

"lat" : 39.99331

}

}

]

}

之前线上碰到过诡异的问题,更新member的昵称不生效

之前的更新逻辑是,取出memberList,根据uid找到要修改的member,修改之后将memberList写入进去,更新代码示例如下:

// 因为写入的是整个memberList,所以在并发修改的场景下,就会出现相互覆盖的问题

// 有问题的时间序:A、B同时读取memberList -> A修改自己的数据并将memberList写库 -> B修改自己的数据并将memberList写库

// 这样B的更新就会将A的更新覆盖掉

collection.updateOne(eq("_id", new ObjectId("5eb17213bcab265fc1959eb7")), new Document("$set", new Document("memberList", memberList)));

要解决这个问题可以考虑不使用内嵌文档结构,使用经典结构,将member单独开一个collection,就不会有问题了

在不改动库表结构的前提下,想要避免这种问题,就需要做到只更新memberList中满足条件的member的指定字段。注意这里是两步,1是找到要更新的member,2是只更新member中的指定字段,这样就会避免覆盖掉其他member或者同一个member中的其他字段了

可以考虑使用$占位符或者mongo3.6之后的arrayFilter来更新,示例如下:

// 使用$占位符更新(只会更新memberList中uid为1的第一个member)

collection.updateOne(combine(eq("_id", objectId), eq("memberList.uid", "1")), new Document("$set", new Document("memberList.$.nickName", "哈哈哈")));

// 使用arrayFilter更新(memberList中uid为1的member都会被更新),只有mongo3.6以后版本支持

collection.updateOne(eq("_id", objectId), new Document("$set", new Document("memberList.$[elem].nickName", "哈哈哈")), new UpdateOptions().arrayFilters(Arrays.asList(eq("elem.uid", "1")));

mongo中对数组的操作需要想的多一点,增加用push,删除用pull,不要直接用set更新整个数据,否则还是会有覆盖问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值