为了账号安全,请及时绑定邮箱和手机立即绑定

使用过滤器中的值更新文档

使用过滤器中的值更新文档

Go
小怪兽爱吃肉 2022-05-18 13:49:21
我在 MongoDB 中有一个具有以下结构的集合:{  "userId": String,  "refs": Set<String>}我需要用这些文档更新集合。我想为refsfilter 中的用户添加一个新字符串$in。但是,如果用户不存在,我需要“更新”他。在代码(golang)中,它看起来像这样:filter := bson.M{    "userId": bson.M{        "$in:": tokens // tokens is []string    }}update := bson.M{    "$addToSet": bson.M{        "refs": newReference    }}ctx, _ := newDbOperationContext()_, err := driver.UpdateMany(ctx, filter, update)因此,对于现有用户来说它工作正常,添加了参考。但是,对于不存在的用户,什么都不会发生。我设置了driver.UpdateMany(bson, bson, opts...)opts to options.UpdateOptions.SetUpsert(true)",但结果我得到了一个没有 userId 的文档:{  "_id": ObjectId("..."),  "refs": ["new_reference"]}所以,我的问题是,如何用userId字段更新新值。规模就像要更新 2*10^6 个用户,所以我想使用批处理请求来做到这一点。我认为,使用“一个一个”创建并更新他不是一个选项。谢谢你的支持!
查看完整描述

3 回答

?
LEATH

TA贡献1936条经验 获得超6个赞

根据之前在 SO 中的问题,例如这个和另一个,似乎不可能upserts仅使用$in运算符执行多个,因为它只会插入一个文档(与过滤器匹配的那个):


如果没有文档与查询条件匹配,则 db.collection.update() 插入单个文档。


因此,正如@Kartavya 所提到的,最好的方法是使用BulkWrite.


为此,您需要为每个用户附加一个 upsert 操作(= WriteModel)tokens作为过滤器,并且您可以使用相同的$addToSet更新操作:


tokens := [...]string{"userId1", "userId3"}

newRef := "refXXXXXXX"


// all docs can use the same $addToSet update operation

updateOp := bson.D{{"$addToSet", bson.D{{"refs", newRef}}}}


// we'll append one update for each userId in tokens as a filter

upserts := []mongo.WriteModel{}

for _, t := range tokens {

    upserts = append(

        upserts,

        mongo.NewUpdateOneModel().SetFilter(bson.D{{"userId", t}}).SetUpdate(updateOp).SetUpsert(true))

}


opts := options.BulkWrite().SetOrdered(false)

res, err := col.BulkWrite(context.TODO(), upserts, opts)

if err != nil {

    log.Fatal(err)

}


fmt.Println(res)


查看完整回答
反对 回复 2022-05-18
?
catspeake

TA贡献1111条经验 获得超0个赞

查看您的用例,我认为最好的解决方案如下:

由于您的规模很大并且希望进行批量请求,因此最好使用 BulkWrite : db.collection.bulkWrite() 方法提供了执行批量插入、更新和删除操作的能力。示例:https ://godoc.org/go.mongodb.org/mongo-driver/mongo#example-Collection-BulkWrite

这使用 UpdateOne 模型,但它也支持 UpdateMany 模型。它也是 SetUpsert(true) 的一个功能 现在对于 _id 字段:您更新/更新的文档应该具有 _id 字段,以便新文档具有该 _id 字段,否则 mongoDb 会在插入文档时自动生成一个 _id 字段,如果您的 upsert 文档有没有 _id 字段

我认为,在您的文档中包含 _id 字段不会很痛苦,这样您的问题就解决了。

关于规模,我建议将 BulkWrite 与 UpdateOne 或 UpdateMany 模型一起使用。


查看完整回答
反对 回复 2022-05-18
?
手掌心

TA贡献1942条经验 获得超3个赞

在 upsert 的情况下,如果文档不存在,那么只有查询的更新部分会插入到数据库中。所以这就是为什么你的输出是这样的。你可以在这里看到。


查看完整回答
反对 回复 2022-05-18
  • 3 回答
  • 0 关注
  • 100 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信