mongo的$push与$setOnInsert冲突解决

mongo的$push与$setOnInsert冲突解决

业务需求 update时集合中若不存在则插入文档,若存在则将该文档的一个数组字段添加一个元素。

示例

# 集合中一开始不存在name为1的文档,插入该文档
doc = {'name':1,'year':[2000]}
# 现在集合中有name为1的文档,则将year为2001添加到上面的文档中的year字段中
doc = {'name':1,'year':[2001]}

满足这个需求使用$push,$setOnInsert,upsert即可完成,但存在易错点。

以下代码使用pymongo

错误写法

col.update({'name': 1}, {
'$push': {'year': doc['year']},'$setOnInsert':doc}, upsert=True)

如果写成上面这样,会报如下错误

pymongo.errors.WriteError: Updating the path 'year' would create a conflict at 'year', full error: {'index': 0, 'code': 40, 'errmsg': "Updating the p
ath 'year' would create a conflict at 'year'"}

原因是$push无论文档是否存在都会做出添加操作,而$setOnInsert有可能会插入doc文档,文档中又有year字段,则会产生冲突。

正确使用

将year单独存一个变量放在push语句中,doc不能存在year键值对

doc = {'name':1,'year':[2001]}
year = doc.pop('year')
col.update({'name': 1}, {
'$push': {'year':year},'$setOnInsert':doc}, upsert=True)

由于$push无论文档是否存在都会做出添加操作(存在则直接添加,不存在会创建同名数组字段后添加),而$setOnInsert在文档不存在的时候才会插入相应字段,所以不存在时插入的文档是刚好完整的,而存在时更新只会添加一个year字段的元素。

$push与$set也会冲突,解决方法相似。

posted @ 2022-01-12 23:57  lymmurrain  阅读(295)  评论(0编辑  收藏  举报