MongoDB в Go (golang) с mgo: Как обновить запись, узнать, было ли обновление успешным и получить данные в одной атомной операции?
Я использую драйвер mgo для MongoDB под Go.
Мое приложение запрашивает задачу (только с записью в Mongo из коллекции, называемой "jobs" ), а затем регистрируется как asignee для выполнения этой задачи (обновление этой же записи "job", установка себя как правопреемник).
Программа будет работать на нескольких машинах, все говорят с одним и тем же Монго. Когда моя программа перечисляет доступные задачи, а затем выбирает один, другие экземпляры могли бы уже получить это назначение, и текущее назначение не получилось бы.
Как я могу убедиться, что запись, которую я прочитал, а затем обновить, имеет или не имеет определенного значения (в данном случае, правопреемника) во время обновления?
Я пытаюсь получить одно задание, независимо от того, какой именно, поэтому я должен сначала выбрать ожидающую задачу и попытаться назначить ее, сохранив ее только в том случае, если обновление было успешным.
Итак, мой запрос должен выглядеть примерно так:
"Из всех записей в" заданиях коллекции "обновите только один, у которого есть asignee = null, установив мой идентификатор в качестве правопреемника. Затем дайте мне эту запись, чтобы Я мог бы выполнить задание.
Как я могу выразить это с помощью драйвера mgo для Go?
Ответы
Ответ 1
Надеюсь, вы видели комментарии к выбранному вами ответу, но этот подход неверен. Выполнение выбора и последующего обновления приведет к обращению в оба конца и двум машинам и будет загружаться для одной и той же работы, прежде чем один из них сможет обновить assignee
. Вместо этого вы должны использовать метод findAndModify
: http://www.mongodb.org/display/DOCS/findAndModify+Command
Ответ 2
Это старый вопрос, но на всякий случай кто-то все еще смотрит дома, это хорошо поддерживается с помощью метода 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)
Ответ 3
Ребята из MongoDB описывают аналогичный сценарий в официальной документации: http://www.mongodb.org/display/DOCS/Atomic+Operations
В принципе, все, что вам нужно сделать, - это получить любое задание с помощью assignee=null
. Предположим, вы получили работу с помощью _id=42
назад. Затем вы можете изменить документ локально, установив assignee="worker1.example.com"
и вызовите Collection.Update() с помощью селектора {_id=42, assignee=null}
и вашего обновленный документ. Если база данных все еще может найти документ, соответствующий этому селектору, он будет атомизировать документ. В противном случае вы получите ErrNotFound, указав, что другой поток уже выполнил задачу. В этом случае повторите попытку.