MongoTemplate中setOnInsert与set方法的深度解析
在Spring Data MongoDB的MongoTemplate
中,setOnInsert
和set
方法都是在更新文档时使用的,但它们在处理upsert
操作(即,如果文档不存在则插入,存在则更新)时扮演着截然不同的角色。
核心区别:操作的触发时机
setOnInsert
和set
最核心的区别在于它们执行的条件:
set()
: 无论操作是更新现有文档还是插入新文档,set()
方法指定的字段都会被设置或更新。setOnInsert()
:setOnInsert()
方法指定的字段仅在upsert
操作导致新文档被插入时才会被设置。如果upsert
操作匹配到了现有文档并进行更新,那么setOnInsert()
中的设置将被忽略。
可以简单地理解为,setOnInsert
是为新插入的文档设置一个初始值或默认值,而set
则是对文档进行常规的更新。
使用场景与代码示例
setOnInsert
和set
通常与upsert: true
选项结合使用。 upsert
为true
意味着,如果查询条件没有找到匹配的文档,MongoDB将会创建一个新的文档。
场景示例: 假设我们有一个products
集合,我们希望在产品首次被添加到数据库时设置一个默认的库存数量(defaultQty
),同时在每次更新时都更新产品的名称(item
)。
使用MongoTemplate
实现:
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
// ...
public void upsertProduct(MongoTemplate mongoTemplate, String productId, String itemName) {
Query query = new Query(Criteria.where("_id").is(productId));
Update update = new Update()
.set("item", itemName)
.setOnInsert("defaultQty", 100);
mongoTemplate.upsert(query, update, "products");
}
操作结果分析:
-
当
productId
对应的文档不存在时:upsert
操作会创建一个新的文档。set("item", itemName)
会被执行,新文档的item
字段被设置为itemName
。setOnInsert("defaultQty", 100)
也会被执行,新文档的defaultQty
字段被设置为100
。- 最终插入的文档为:
{ "_id": productId, "item": "newItemName", "defaultQty": 100 }
-
当
productId
对应的文档已存在时:upsert
操作会匹配到现有的文档。set("item", itemName)
会被执行,现有文档的item
字段被更新为新的itemName
。setOnInsert("defaultQty", 100)
将被忽略,因为没有发生插入操作。- 如果原文档是
{ "_id": productId, "item": "oldItemName", "defaultQty": 50 }
,更新后的文档将是{ "_id": productId, "item": "newItemName", "defaultQty": 50 }
。
注意事项
- 字段不能重复: 在同一个
Update
对象中,同一个字段不能同时出现在set()
和setOnInsert()
中,否则会引发错误。 upsert
是关键:setOnInsert
的效果完全依赖于upsert
操作。如果upsert
为false
(默认情况),setOnInsert
将永远不会生效。
总结
总的来说,set
和setOnInsert
为在MongoTemplate
中执行upsert
操作提供了强大的灵活性:
方法 | 描述 | 使用场景 |
---|---|---|
set() | 无论文档是插入还是更新,都设置或更新指定的字段。 | 需要对字段进行常规更新,不论其是否存在。 |
setOnInsert() | 仅在upsert 操作插入新文档时设置指定的字段。 | 为新创建的文档设置创建时间、初始状态、默认值等一次性属性。 |