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也会冲突,解决方法相似。