Mongodb 如何一次更新多个子文档
发布于 4 年前 作者 booxood 8328 次浏览 最后一次编辑是 3 年前 来自 问答

mongodb collection 的数据结构:

{
	"_id" : ObjectId("55718373d8a2c1b66a746d34"),
	"a" : "a1",
	"b" : {
		"b1" : [
			{
				"k1" : "v1",
				"k2" : "v2"
			},
			{
				"k1" : "v1",
				"k2" : "v2"
			}
		],
		"b2" : [
			{
				"k1" : "v1",
				"k2" : "v2"
			},
			{
				"k1" : "no no no",
				"k2" : "v2"
			}
		]
	}
}

如何更新把 ( b.b1.k1 = “v1” || b.b2.k1 == “v1” ) 的子文档都更新为 b.*.k2 = “ok”?

可能不太好理解,其实就是希望可以更新操作一次完成,变成下面这样:

{
{
	"_id" : ObjectId("55718373d8a2c1b66a746d34"),
	"a" : "a1",
	"b" : {
		"b1" : [
			{
				"k1" : "v1",
				"k2" : "ok"
			},
			{
				"k1" : "v1",
				"k2" : "ok"
			}
		],
		"b2" : [
			{
				"k1" : "v1",
				"k2" : "ok"
			},
			{
				"k1" : "no no no",
				"k2" : "v2"
			}
		]
	}
}
}

把 b1、b2 里 k1 == “v1” 的子文档的 k2 都更新成了 “ok” 。

7 回复

mongodb中并没有标准的方式可以更新子文档的数据,但提供更新多个文档的方式,上述所描述的为聚合设计模型如果想要更新数组内所有数据,可以采取find然后forEach更新的模式。建议看下mongodb权威指南,因为这中设计模式存在一定的风险,数据结构的多层嵌套不利于查询,而数组的无限制(并不是指你)增至更是致命的。

@haozxuan 谢谢答复,这样多层嵌套确实不太好。。。

这里不仅是 想要更新数组内所有数据,还想同时更新 b 的属性 b1b2 各自的数组。。。

不知道能不能一次更新操作办到。。。

@booxood 既然你的更新点比较多,那就更不建议使用聚合类设计模型了,因为这种设计模式在更新时会比较慢。(原因之一是有可能超过写入时申请的空间,需要重新申请空间等)

@haozxuan 嗯,这样的设计确实不好。谢谢。

另外,我觉的 mongodb 不能做到这样的 update 操作。。。不知道是不是这样。。。

@booxood 今天在看2015年回顾时候看到(Mabolo)看到你的评论,发现上次竟然忘记回复你了。前一段时间研究mongodb,后续就被其他工作事情耽误了。 言归正题,首先你的update需求是可以满足的,不过效率的话没有具体实践,单从demo上不太好说,说下思路:对于你update一个doc的多个嵌套可以采用AggregationCursor,实质上是在mongodb内存中做完遍历、update,对应用层透明,理论上没有问题,但如果采用该方式需要考虑一个阀值,在mongodb中单个doc有16M的大小限制,对AggregationCursor也有相应的限制,具体可以了解下聚合update规则,只要保证不会超过阀值,这不失是一种解决方式。:)

@haozxuan 哈哈 亏你有心还翻出来。。。我都忘了最后是怎么处理的了。。。 我理解 aggregate 是用来做统计查询的,可以 update doc 吗? 在 aggregate 时最大内存限制可以通过设置 allowDiskUse=true 吧。Perform Large Sort Operation with External Sort

@booxood 可以的,可以做一些复杂运算。不过我担心的是单个连接内存和总内存之前的平衡,假如一个聚合update使用了10M内存,mongodb服务只有4G内存,那么即使连接数没有限制,由于内存瓶颈,最终能够建立的连接也只有410个左右。所以这个东西还是有待优化的。

回到顶部