Simulating an Upsert with mgo.txn

huangapple go评论109阅读模式
英文:

Simulating an Upsert with mgo.txn

问题

由于mgo/txn中没有Upsert操作,当我不知道文档是否已存在时,我会先进行插入操作,然后再进行更新操作。就像这样(请注意,这只是一个简单的示例,在实际情况中,我还会更改其他文档)--

ops := []txn.Op{{
    C:      "test",
    Id:     t.Id,
    Insert: t,
}, {
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": bson.M{"num": 123}},
}}

这个方法可以正常工作。不幸的是,它要求我准确地知道哪些字段已更改。通常,我会在一个Save()函数中运行这个操作,该函数接收一个对象并保存一系列相关文档,所以我通常不知道哪些字段已更改。我尝试了以下方法--

ops := []txn.Op{{
    C:      "test",
    Id:     t.Id,
    Insert: t,
}, {
    C:      "test",
    Id:     t.Id,
    Update: t,
}}

但是这似乎不起作用,因为我得到了一个"Modifiers and non-modifiers cannot be mixed"的错误。我唯一想到的解决办法是逐个"$set"每个字段--

ops := []txn.Op{{
    C:      "test",
    Id:     t.Id,
    Insert: t,
}, {
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": bson.M{"num": 123}},
}, {
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": bson.M{"other": 234}},
}}

但是这种方法看起来有些笨拙。我是否遗漏了什么?是否有一种更新整个文档的方法?

英文:

Since there's no Upsert in mgo/txn, I'm doing an Insert followed by an Update when I don't know whether a document already exists. Like this (bear in mind this is a simple example, in reality I would also be changing different documents) --

ops := []txn.Op{{
    C:      "test",
    Id:     t.Id,
    Insert: t,
}, {
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": bson.M{"num": 123}},
}}

This works fine. Unfortunately it requires me to know exactly which fields have been changed. I normally run this inside a Save() function that receives an object and saves a bunch of related documents so I don't usually know what fields have been changed. I tried doing something like this instead --

ops := []txn.Op{{
    C:      "test",
    Id:     t.Id,
    Insert: t,
}, {
    C:      "test",
    Id:     t.Id,
    Update:t,
}}

But that doesn't seem to work as I get a "Modifiers and non-modifiers cannot be mixed" error. The only solution I came up with was to "$set" every individual field --

ops := []txn.Op{{
    C:      "test",
    Id:     t.Id,
    Insert: t,
}, {
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": bson.M{"num": 123}},
}, {
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": bson.M{"other": 234}},
}}

But this seems... clunky. Am I missing something? Is there a way to update the whole document?

答案1

得分: 2

尽管你将重新发送所有内容看起来有点可疑,但你可以通过将值本身提供给$set来设置值中的每个字段:

{
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": t},
}

还要注意,即使你选择手动发送值,也没有理由将它们分成多个操作;以下方式也可以工作:

{
    C:      "test",
    Id:     t.Id,
    Update: bson.M{"$set": bson.M{"foo": 1, "bar": 2}},
}

最后,请记住,当你在事务机制中使用文档时,它会获得一些对于机制本身来说是必要的额外字段。如果你用自定义内容替换整个文档,这些字段将消失,txn包将无法正常工作。

英文:

Although it looks a bit dubious given you'll be resending all the content over again, you can set every field in a value by offering the value itself to $set:

    {
        C:      "test",
        Id:     t.Id,
        Update: bson.M{"$set": t},
    }

Also note that even if you choose to send the values manually, there's no reason to send them in multiple operations; this would work:

    {
        C:      "test",
        Id:     t.Id,
        Update: bson.M{"$set": bson.M{"foo": 1, "bar": 2}},
    }

Finally, please keep in mind that when you use a document with the transaction machinery, it gets extra fields which are necessary for the machinery itself. If you replace the whole document with some custom content, these fields will go away, and the txn package won't behave properly.

huangapple
  • 本文由 发表于 2014年6月27日 23:27:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/24455478.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定