2012-07-10 8 views
10

Używam sterownika mgo dla MongoDB w trybie Go.MongoDB in Go (golang) z mgo: Jak zaktualizować rekord, sprawdzić, czy aktualizacja się powiodła i uzyskać dane w pojedynczej operacji atomowej?

Moja aplikacja prosi o zadanie (z wybranym rekordem w Mongo z kolekcji o nazwie "jobs"), a następnie rejestruje się jako osoba upoważniona do wykonania tego zadania (aktualizacja tego samego rekordu "job", ustawienie się jako cesjonariusz).

Program będzie działał na kilku komputerach, wszystkie rozmawiają z tym samym Mongo. Gdy mój program wyświetli listę dostępnych zadań, a następnie wybierze jedną z nich, inne instancje mogły już uzyskać to zadanie, a bieżące zadanie nie powiodło się.

Jak mogę się upewnić, że rekord, który czytałem, a następnie aktualizuję, ma lub nie ma określonej wartości (w tym przypadku cesjonariusza) w momencie aktualizacji?

Próbuję uzyskać jedno zadanie, bez względu na to, więc myślę, że najpierw powinienem wybrać oczekujące zadanie i spróbować je przypisać, zachowując je w przypadku, gdy aktualizacja zakończyła się pomyślnie.

Więc moje zapytanie powinno być coś takiego:

„ze wszystkich zapisów dotyczących«Jobs»zbieranie, zaktualizuj tylko jeden że ma asignee = null, ustawienie identyfikatora jako cesjonariuszem Potem mi dać. to nagranie, abym mógł wykonać pracę. "

Jak mogę wyrazić to za pomocą sterownika mgo dla Go?

Odpowiedz

2

Mam nadzieję, że zobaczyłeś komentarze na temat wybranej odpowiedzi, ale to podejście jest nieprawidłowe. Wykonanie operacji wyboru, a następnie aktualizacji spowoduje wykonanie podróży w obie strony i dwóch komputerów oraz pobranie tej samej pracy, zanim jeden z nich zaktualizuje numer assignee. Trzeba użyć metody findAndModify Zamiast: http://www.mongodb.org/display/DOCS/findAndModify+Command

+0

Właściwie to, czego potrzebuję, to jeden z oferowanych tux21b. Muszę odzyskać wszystkie "opcje", a następnie wybrać jedną, a następnie spróbować przypisać ją sobie. Jeśli się nie uda, spróbuję z innym. –

+0

Dlaczego musisz wybrać WSZYSTKIE opcje? Czy powiedziałeś, że musisz wybrać tylko to, co nie zostało podjęte (aka assignee == null)? –

+0

Masz rację. Moje potrzeby okazały się inne niż te, które myślałem, gdy pisałem pytanie, ale twoja odpowiedź lepiej pasuje do tego pytania. –

2

MongoDB faceci opisać podobny scenariusz w oficjalnej dokumentacji: http://www.mongodb.org/display/DOCS/Atomic+Operations

Zasadniczo, wszystko co musisz zrobić, to pobrać każdą pracę z assignee=null. Załóżmy, że dostaniesz pracę z powrotem z numerem _id=42. Możesz następnie zmodyfikować dokument lokalnie, ustawiając assignee="worker1.example.com" i dzwoniąc pod numer Collection.Update() za pomocą selektora {_id=42, assignee=null} i zaktualizowanego dokumentu. Jeśli baza danych nadal może znaleźć dokument zgodny z tym selektorem, zastąpi on dokument atomicznie. W przeciwnym razie otrzymasz ErrNotFound, co oznacza, że ​​inny wątek już odebrał to zadanie. Jeśli tak, spróbuj ponownie.

+4

Performing wybierz następuje aktualizacja nie jest atomowy; wykonuje dwie podróże w obie strony! Polecenie findAndModify wykona tę operację atomowo. Mongo docs dla tego polecenia są tutaj: http://www.mongodb.org/display/DOCS/findAndModify+Command MgO docs dla robią to w Go są tutaj: http://go.pkgdoc.org/labix .org/v2/mgo # Zapytanie.Zastosuj – jorelli

+1

Aktualizacja select + nie musi być atomowa dla tego konkretnego algorytmu. Dopóki sama aktualizacja jest atomowa (co jest w zasadzie operacją CompareAndSwap/CompareExchange), wszystko jest w porządku. – tux21b

+1

Jeśli dwa urządzenia wybierają to samo zadanie w pierwszym zapytaniu, jeden z nich nie powiedzie się w aktualizacji. Oczywiście, końcowym rezultatem może być zawsze to, że dane w bazie danych nigdy nie będą niespójne, ale przypadek awarii przy użyciu dwóch oddzielnych operacji powoduje wiele niepotrzebnych tam iz powrotem. To jest ... cały powód, dla którego istnieje polecenie findAndModify. – jorelli

41

To stara sprawa, ale tylko w przypadku, gdy ktoś jest nadal oglądać w domu, to jest ładnie obsługiwanej metodą Query.Apply. Wykonuje polecenie findAndModify, jak wskazano w innej odpowiedzi, ale jest wygodnie ukryte za Go dobroci.

Przykład w dokumentacji odpowiada prawie dokładnie to pytanie tutaj:

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)