10

我在 Go 下为 MongoDB 使用 mgo 驱动程序。

我的应用程序请求一个任务(仅在 Mongo 中从名为“jobs”的集合中选择一个记录),然后将自己注册为受让人以完成该任务(对同一“工作”记录的更新,将自己设置为受让人)。

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

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

我正在尝试获得一项任务,无论是哪一项,所以我认为我应该首先选择一个待处理的任务并尝试分配它,以防万一更新成功。

所以,我的查询应该是这样的:

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

我怎么能用 Go 的 mgo 驱动程序来表达呢?

4

3 回答 3

42

这是一个老问题,但万一有人还在家里看,Query.Apply方法很好地支持了这一点。它确实运行了findAndModify另一个答案中指示的命令,但它方便地隐藏在 Go goodness 后面。

文档中的示例与此处的问题几乎完全匹配:

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)
于 2013-08-20T23:24:55.860 回答
2

MongoDB 的家伙在官方文档中描述了类似的场景:http ://www.mongodb.org/display/DOCS/Atomic+Operations

基本上,您所要做的就是使用assignee=null. 假设你得到了_id=42背部的工作。然后,您可以继续在本地修改文档,方法是使用选择器和更新的文档设置assignee="worker1.example.com"和调用Collection.Update() 。{_id=42, assignee=null}如果数据库仍然能够找到与此选择器匹配的文档,它将自动替换该文档。否则你会得到一个 ErrNotFound,表明另一个线程已经认领了这个任务。如果是这种情况,请再试一次。

于 2012-07-10T17:41:47.350 回答
2

我希望您看到对您选择的答案的评论,但这种方法是不正确的。进行选择然后更新将导致往返和两台机器,并且在其中一台可以更新assignee. 您需要改用该findAndModify方法:http ://www.mongodb.org/display/DOCS/findAndModify+Command

于 2012-09-10T15:35:27.833 回答