Подтвердить что ты не робот

MongoDB в Go (golang) с mgo: Как обновить запись, узнать, было ли обновление успешным и получить данные в одной атомной операции?

Я использую драйвер mgo для MongoDB под Go.

Мое приложение запрашивает задачу (только с записью в Mongo из коллекции, называемой "jobs" ), а затем регистрируется как asignee для выполнения этой задачи (обновление этой же записи "job", установка себя как правопреемник).

Программа будет работать на нескольких машинах, все говорят с одним и тем же Монго. Когда моя программа перечисляет доступные задачи, а затем выбирает один, другие экземпляры могли бы уже получить это назначение, и текущее назначение не получилось бы.

Как я могу убедиться, что запись, которую я прочитал, а затем обновить, имеет или не имеет определенного значения (в данном случае, правопреемника) во время обновления?

Я пытаюсь получить одно задание, независимо от того, какой именно, поэтому я должен сначала выбрать ожидающую задачу и попытаться назначить ее, сохранив ее только в том случае, если обновление было успешным.

Итак, мой запрос должен выглядеть примерно так:

"Из всех записей в" заданиях коллекции "обновите только один, у которого есть asignee = null, установив мой идентификатор в качестве правопреемника. Затем дайте мне эту запись, чтобы Я мог бы выполнить задание.

Как я могу выразить это с помощью драйвера mgo для Go?

4b9b3361

Ответ 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, указав, что другой поток уже выполнил задачу. В этом случае повторите попытку.