ᕕ( ᐛ )ᕗ Jimyag's Blog

在 MongoDB 中不依赖唯一索引如何避免并发重复插入

使用 MongoDB 时,我们经常需要避免并发重复插入。通常情况下,我们会使用唯一索引,但有时我们可能无法使用唯一索引,或者唯一索引的性能开销太大。本文将介绍一种不依赖唯一索引的解决方案。

使用 setOnInsert 来避免重复插入。

func InsertOneIfNotExists(ctx context.Context, coll *mongo.Collection, filter bson.M, setOnInsert bson.M) error {
	opts := options.Update().SetUpsert(true)
	update := bson.M{"$setOnInsert": setOnInsert}
	res, err := coll.UpdateOne(ctx, filter, update, opts)
	if err != nil {
		return err
	}
	if res.MatchedCount == 0 {
		return nil
	} else {
		// 如果文档已存在,返回重复键错误
		return mongo.WriteError{
			Code: 11000, // MongoDB 重复键错误码
		}
	}
}

UpdateOne 方法的 upsert 参数为 true 时,如果文档不存在,则插入文档,如果文档存在,则更新文档。

UpdateOne 也是原子操作,不会被其他操作中断。

$setOnInsert 用于设置插入操作的值,如果文档不存在,则插入文档,如果文档存在,则不插入。

$setOnInsert 的值不会覆盖已存在的值,只会插入不存在的值。

返回的 res 中,MatchedCount 表示匹配到的文档数量,UpsertedID 表示插入的文档 ID。

如果 MatchedCount 为 0,则表示文档不存在,则插入文档,如果 MatchedCount 为 1,则表示文档存在,则更新文档。

#Mongodb