Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go中的MongoDB(golang)和mgo:如何更新记录,找出更新是否成功,并在单个原子操作中获取数据?_Mongodb_Go_Mgo - Fatal编程技术网

Go中的MongoDB(golang)和mgo:如何更新记录,找出更新是否成功,并在单个原子操作中获取数据?

Go中的MongoDB(golang)和mgo:如何更新记录,找出更新是否成功,并在单个原子操作中获取数据?,mongodb,go,mgo,Mongodb,Go,Mgo,我正在使用mgo驱动程序进行MongoDB下围棋 我的应用程序要求执行一项任务(在Mongo中只需从一个名为“jobs”的集合中选择一条记录),然后将自己注册为受让人以完成该任务(更新同一条“job”记录,将自己设置为受让人) 该程序将在多台机器上运行,所有机器都与同一个Mongo对话。当我的程序列出可用任务,然后选择一个时,其他实例可能已经获得该分配,而当前分配将失败 如何确保我读取并随后更新的记录在更新时是否具有特定值(在本例中为受让人) 我试图得到一个任务,无论是哪一个,所以我认为我应该首

我正在使用mgo驱动程序进行MongoDB下围棋

我的应用程序要求执行一项任务(在Mongo中只需从一个名为“jobs”的集合中选择一条记录),然后将自己注册为受让人以完成该任务(更新同一条“job”记录,将自己设置为受让人)

该程序将在多台机器上运行,所有机器都与同一个Mongo对话。当我的程序列出可用任务,然后选择一个时,其他实例可能已经获得该分配,而当前分配将失败

如何确保我读取并随后更新的记录在更新时是否具有特定值(在本例中为受让人)

我试图得到一个任务,无论是哪一个,所以我认为我应该首先选择一个挂起的任务,并尝试分配它,保持它只是在更新成功的情况下

因此,我的查询应该是这样的:

“从集合“作业”上的所有记录中,仅更新一个assignee=null的记录,将我的ID设置为assignee。然后,将该记录提供给我,以便我可以运行作业。”


我如何用mgo driver for Go来表达这一点?

MongoDB的人在官方文档中描述了类似的场景:


基本上,您所要做的就是使用
assignment=null
获取任何作业。让我们假设您获得了返回
\u id=42
的作业。然后,通过设置
assignee=“worker1.example.com”
并使用选择器调用
{u id=42,assignee=null}
和更新的文档,您可以继续在本地修改文档。如果数据库仍然能够找到与此选择器匹配的文档,它将自动替换该文档。否则,您将得到一个ErrNotFound,表示另一个线程已经声明了该任务。如果是这样的话,请再试一次。

我希望您看到了对所选答案的评论,但这种方法是不正确的。执行选择然后更新将导致一次往返,两台机器在其中一台机器可以更新
受让人之前将获取相同的作业。您需要使用
查找并修改
方法:

这是一个老问题,但万一有人仍在家中观看,该方法很好地支持了这一点。它确实运行
findanddomify
命令,如另一个答案所示,但它方便地隐藏在Go Goods后面

文档中的示例与此处的问题非常吻合:

change := mgo.Change{
        Update: bson.M{"$inc": bson.M{"n": 1}},
        ReturnNew: true,
}
info, err = col.Find(M{"_id": id}).Apply(change, &doc)
fmt.Println(doc.N)

在更新之后执行选择不是原子的;它执行两次往返!findAndModify命令将以原子方式执行此操作。此命令的Mongo文档在这里:在Go中执行此操作的Mgo文档在这里:对于此特定算法,select+更新不需要是原子的。只要更新本身是原子的(基本上是一个CompareAndSwap/compareeexchange操作),一切都很好。如果两台计算机在第一次查询中选择了相同的作业,其中一台将在更新时失败。当然,最终的结果可能总是数据库中的数据永远不会变得不一致,但是使用两个单独操作的失败案例会导致大量不必要的来回。这是。。。findAndModify命令存在的全部原因。实际上,我需要的解决方案是tux21b提供的解决方案。我需要重新查看所有“选项”,然后选择一个,然后尝试将其分配给我自己。如果不成功,我会尝试另一个。为什么需要选择所有选项?你是说你只需要选择一个没有被接受的(aka assignment==null)?你是对的。事实证明,我的需求与我写问题时的想法不同,但您的答案更符合问题。mgo通过该方法方便地支持findAndModify命令。有关详细信息,请参见下面的答案。