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

使用 `setOnInsert` 来避免重复插入。

```go
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，则表示文档存在，则更新文档。

