upsert()

语法

db.collectionspace.collection.upsert(<rule>,[cond],[hint],[setOnInsert],[options])

更新集合记录。upsert 方法跟 update 方法都是对记录进行更新,不同的是当使用 cond 参数在集合中匹配不到记录时,update 不做任何操作,而 upsert 方法会做一次插入操作。

参数描述

参数名参数类型描述是否必填
ruleJson 对象更新规则。记录按 rule 的内容更新。
condJson 对象选择条件。为空时,更新所有记录,不为空时,更新符合条件的记录。
hintJson 对象指定访问计划。
setOnInsertJson 对象在做插入操作时向插入的记录中追加字段。
optionsJson 对象可选项,详见options选项说明。

options选项

参数名参数类型描述默认值
KeepShardingKeybool为 false 时,将不保留更新规则中的分区键字段,只更新非分区键字段。为 true 时,将会保留更新规则中的分区键字段。false

Note:

  • 参数hint的用法与find()的相同。

  • cond 参数在集合中匹配不到记录时,upsert 会生成一条记录插入到集合中。记录生成规则为:首先从 cond 参数中取出 $et 和 $all 操作符对应的键值对,没有的时候生成空记录。然后使用 rule 规则对其做更新操作,最后加入 setOnInsert 中的键值对。

  • 目前分区集合上,不支持更新分区键。如果 KeepShardingKey 为 true,并且更新规则中带有分区键字段,将会报错-178。

返回值

  • 成功返回详细结果信息(BSONObj 对象),结构如下:
  1. {
  2. UpdatedNum : <INT64> 成功更新的记录数,包括匹配但未发生数据变化的记录,
  3. ModifiedNum : <INT64> 成功更新且发生数据变化的记录数,
  4. InsertedNum : <INT32> 成功插入的记录数,仅在 upsert 下生效
  5. }
  • 出错抛异常,并输出错误信息,可以通过getLastErrMsg()获取错误信息或通过getLastError()获取错误信息码。错误信息对象包括详细结果信息。

错误

错误信息记录在节点诊断日志(diaglog)中,可参考错误码

错误码可能的原因解决方法
-178分区集合上不支持更新分区键KeepShardingKey 设置为 false,不更新分区键

示例

假设集合 bar 中有两条记录:

  1. {
  2. "_id": {
  3. "$oid": "516a76a1c9565daf06030000"
  4. },
  5. "age": 10,
  6. "name": "Tom"
  7. }
  8. {
  9. "_id": {
  10. "$oid": "516a76a1c9565daf06050000"
  11. },
  12. "a": 10,
  13. "age": 21
  14. }
  • 按指定的更新规则更新集合中所有记录,即设置 rule 参数,不设定 cond 和 hint 参数的内容。如下操作等效于使用 update 方法,更新集合 bar 中的所有记录,使用$inc将记录的 age 字段值加1,name 字段值更改为“Mike”,对不存在 name 字段的记录,$set 操作符会将 name 字段和其设定的值插入到记录中,可使用 find 方法查看更新结果。
  1. > db.foo.bar.upsert( { $inc: { age: 1 }, $set: { name: "Mike" } } )
  2. {
  3. "UpdatedNum": 2,
  4. "ModifiedNum": 2,
  5. "InsertedNum": 0
  6. }
  7. >
  8. > db.foo.bar.find()
  9. {
  10. "_id": {
  11. "$oid": "516a76a1c9565daf06030000"
  12. },
  13. "age": 11,
  14. "name": "Mike"
  15. }
  16. {
  17. "_id": {
  18. "$oid": "516a76a1c9565daf06050000"
  19. },
  20. "a": 10,
  21. "age": 22,
  22. "name":"Mike"
  23. }
  24. Return 2 row(s).
  • 选择符合匹配条件的记录,对这些记录按更新规则更新,即设定 rule 和 cond 参数。如下操作使用$exists匹配存在 type 字段的记录,使用$inc将这些记录的 age 字段值加3。在上面给出的两条记录中,都没有 type 字段,此时,upsert 操作会插入一条新的记录,新记录只有 _id 字段和 age 字段名,_id 字段值自动生成,而 age 字段值为3。
  1. > db.foo.bar.upsert( { $inc: { age: 3 } }, { type: { $exists: 1 } } )
  2. {
  3. "UpdatedNum": 0,
  4. "ModifiedNum": 0,
  5. "InsertedNum": 1
  6. }
  7. >
  8. > db.foo.bar.find()
  9. {
  10. "_id": {
  11. "$oid": "516a76a1c9565daf06030000"
  12. },
  13. "age": 11,
  14. "name": "Mike"
  15. }
  16. {
  17. "_id": {
  18. "$oid": "516a76a1c9565daf06050000"
  19. },
  20. "a": 10,
  21. "age": 22,
  22. "name":"Mike"
  23. }
  24. {
  25. "_id": {
  26. "$oid": "516cfc334630a7f338c169b0"
  27. },
  28. "age": 3
  29. }
  30. Return 3 row(s).
  • 按访问计划更新记录,假设集合中存在指定的索引名 testIndex,此操作等效于使用 update 方法,使用索引名为 testIndex 的索引访问集合 bar 中 age 字段值大于20的记录,将这些记录的 age 字段名加1。
  1. > db.foo.bar.upsert( { $inc: { age: 1 } }, { age: { $gt: 20 } }, { "": "testIndex" } )
  2. {
  3. "UpdatedNum": 1,
  4. "ModifiedNum": 1,
  5. "InsertedNum": 0
  6. }
  7. >
  8. > db.foo.bar.find()
  9. {
  10. "_id": {
  11. "$oid": "516a76a1c9565daf06050000"
  12. },
  13. "a": 10,
  14. "age": 23,
  15. "name":"Mike"
  16. }
  17. Return 1 row(s).
  • 使用setOnInsert更新记录,由于集合 bar 中 age 字段值大于30的记录为空,upsert在做插入操作时向插入的记录中追加字段{"name":"Mike"}。
  1. > db.foo.bar.upsert( { $inc: { age: 1 } }, { age: { $gt: 30 } }, {}, { "name": "Mike" } )
  2. {
  3. "UpdatedNum": 0,
  4. "ModifiedNum": 0,
  5. "InsertedNum": 1
  6. }
  7. >
  8. > db.foo.bar.find( { "age" : 1, "name": "Mike" } )
  9. {
  10. "_id": {
  11. "$oid": "516a76a1c9565daf06050000"
  12. },
  13. "age":1,
  14. "name":"Mike"
  15. }
  16. Return 1 row(s).
  • 分区集合 foo.bar,分区键为 { a: 1 },含有以下记录
  1. > db.foo.bar.find()
  2. {
  3. "_id": {
  4. "$oid": "5c6f660ce700db6048677154"
  5. },
  6. "a": 1,
  7. "b": 1
  8. }
  9. Return 1 row(s).

指定 KeepShardingKey 参数:不保留更新规则中的分区键字段。只更新了非分区键 b 字段,分区键 a 字段的值没有被更新。

  1. > db.foo.bar.upsert( { $set: { a: 9, b: 9 } }, {}, {}, {}, { KeepShardingKey: false } )
  2. {
  3. "UpdatedNum": 1,
  4. "ModifiedNum": 1,
  5. "InsertedNum": 0
  6. }
  7. >
  8. > db.foo.bar.find()
  9. {
  10. "_id": {
  11. "$oid": "5c6f660ce700db6048677154"
  12. },
  13. "a": 1,
  14. "b": 9
  15. }
  16. Return 1 row(s).

指定 KeepShardingKey 参数:保留更新规则中的分区键字段。因为目前不支持更新分区键,所以会报错。

  1. > db.foo.bar.upsert( { $set: { a: 9 } }, {}, {}, {}, { KeepShardingKey: true } )
  2. (nofile):0 uncaught exception: -178
  3. Sharding key cannot be updated