带有mgo的Go(golang)中的MongoDB:如何更新记录,查找更新是否成功并通过单个原子操作获取数据?
I am using mgo driver for MongoDB under Go.
My application asks for a task (with just a record select in Mongo from a collection called "jobs") and then registers itself as an asignee to complete that task (an update to that same "job" record, setting itself as assignee).
The program will be running on several machines, all talking to the same Mongo. When my program lists the available tasks and then picks one, other instances might have already obtained that assignment, and the current assignment would have failed.
How can I get sure that the record I read and then update does or does not have a certain value (in this case, an assignee) at the time of being updated?
I am trying to get one assignment, no matter wich one, so I think I should first select a pending task and try to assign it, keeping it just in the case the updating was successful.
So, my query should be something like:
"From all records on collection 'jobs', update just one that has asignee=null, setting my ID as the assignee. Then, give me that record so I could run the job."
How could I express that with mgo driver for Go?
我正在Go下使用MongoDB的mgo驱动程序。 p>
我的应用程序询问 一个任务(在Mongo中只有一个记录,该记录是从一个名为“ jobs”的集合中选择的),然后将自己注册为受让人以完成该任务(对同一“ job”记录的更新,将自己设置为受让人)。 p >
该程序将在多台计算机上运行,并且都在同一个Mongo上通信。 当我的程序列出可用任务然后选择一个任务时,其他实例可能已经获得了该任务,而当前任务将失败。 p>
如何确保我读取的记录 然后在更新时update是否具有特定值(在这种情况下为受让人)? p>
我试图获得一项任务,无论是哪一项, 所以我认为我应该首先选择一个待处理的任务并尝试分配它,以防万一更新成功。 p>
所以,我的查询应该是这样的: p >
“从“工作”集合中的所有记录中,更新只有一个 strong>,该接收者为空,将我的ID设置为受让人。然后,给我该记录 strong>,这样我就可以完成工作。” p>
我该如何使用Go的mgo驱动程序来表达这一点? p>
div>
I hope you saw the comments on the answer you selected, but that approach is incorrect. Doing a select and then update will result in a round trip and two machines and be fetching for the same job before one of them can update the assignee
. You need to use the findAndModify
method instead: http://www.mongodb.org/display/DOCS/findAndModify+Command
The MongoDB guys describe a similar scenario in the official documentation: http://www.mongodb.org/display/DOCS/Atomic+Operations
Basically, all you have to do, is to fetch any job with assignee=null
. Let's suppose you get the job with the _id=42
back. You can then go ahead and modify the document locally, by setting assignee="worker1.example.com"
and call Collection.Update() with the selector {_id=42, assignee=null}
and your updated document. If the database is still able to find a document that matches this selector, it will replace the document atomically. Otherwise you will get a ErrNotFound, indicating that another thread has already claimed the task. If that's the case, try again.
This is an old question, but just in case someone is still watching at home, this is nicely supported via the Query.Apply method. It does run the findAndModify
command as indicated in another answer, but it's conveniently hidden behind Go goodness.
The example in the documentation matches pretty much exactly the question here:
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)