2015-10-10 16 views
36

Tak długo szukałem odpowiedzi, ale jestem pewien, że straciłem dobre słowa, żeby opisać, o co mi chodzi.Wepchaj przedmioty do tablicy mongo poprzez mangustę

Zasadniczo mam kolekcję MongoDB nazwie Schemat „Ludzie” dla tej kolekcji jest następujący:

people: { 
     name: String, 
     friends: [{firstName: String, lastName: String}] 
     } 

Teraz mam bardzo podstawowe wyraźnej aplikację, która łączy się z bazą danych i skutecznie tworzy „ludzi "z pustą tablicą przyjaciół.

W drugim miejscu w aplikacji znajduje się formularz umożliwiający dodawanie znajomych. Formularz przyjmuje imię i nazwisko, a następnie POSTs z polem nazwy również w celu odniesienia do właściwego obiektu osób.

Trochę ciężko pracuję, tworząc nowy obiekt znajomego, a następnie "przesuwając" go do tablicy przyjaciół.

Wiem, że kiedy robię to za pośrednictwem konsoli mongo, używam funkcji aktualizacji z $ push jako mojej drugiej argumentacji po kryteriach wyszukiwania, ale nie mogę znaleźć właściwego sposobu na uzyskanie mangusty, aby to zrobić.

db.people.update({name: "John"}, {$push: {friends: {firstName: "Harry", lastName: "Potter"}}}); 

UPDATE: Więc odpowiedź Adrian był bardzo pomocny. Oto, co zrobiłem, aby osiągnąć mój cel.

w moim pliku app.js, ustawić tymczasową trasę korzystając

app.get('/addfriend', users.addFriend); 

gdzie w moich users.js złożyć Mam

exports.addFriend = function (req, res, next) 
{ 
var friend = {"firstName": req.body.fName, "lastName": req.body.lName}; 
Users.findOneAndUpdate({name: req.user.name}, {$push: {friends: friend}}); 
}; 
+0

Widzę, że mogę potencjalnie użyć metody collections.findOneAndUpdate(), ale nie jestem pewien, gdzie ją zaimplementuję? W moim modelu? – Neurax

Odpowiedz

71

Zakładając, var friend = { firstName: 'Harry', lastName: 'Potter' };

Istnieją dwa dostępne opcje:

Zaktualizuj model w pamięci i zapisz (zwykła tablica javascript .Push):

person.friends.push(friend); 
person.save(done); 

lub

PersonModel.update(
    { _id: person._id }, 
    { $push: { friends: friend } }, 
    done 
); 

Zawsze staram i iść do pierwszej opcji, jeśli to możliwe, ponieważ będzie ona respektować więcej korzyści, jakie daje mangusta (haczyki, walidację, etc .).

Jednakże, jeśli wykonujesz wiele równoczesnych zapisów, uderzysz w warunki wyścigowe, gdzie skończysz z nieprzyjemnymi błędami wersji, aby powstrzymać Cię przed zastąpieniem całego modelu za każdym razem i utratą poprzedniego znajomego, którego dodałeś. Więc idź do tego tylko wtedy, gdy jest to absolutnie konieczne.

+0

Myślałem, że druga opcja była w rzeczywistości bezpieczniejsza pod względem równoczesnej ochrony przed zapisem? Czy przypadkiem powiedziałeś to drugie, kiedy chciałeś powiedzieć byłego? –

+5

Tak, właśnie sprawdziłem i (w listopadzie 2017 r.), ** it _IS_ safe **, aby użyć funkcji 'update'' mangusta, podczas gdy ** to _IS NOT_ safe **, aby znaleźć dokument, zmodyfikować go w pamięci, a następnie wywołaj metodę '.save()' na dokumencie.Kiedy mówię, że operacja jest "bezpieczna", oznacza to, że nawet jeśli jedna, dwie lub 50 zmian zostaną zastosowane do dokumentu, wszystkie zostaną pomyślnie zastosowane, a zachowanie aktualizacji będzie zgodne z oczekiwaniami. Zasadniczo manipulowanie w pamięci jest niebezpieczne, ponieważ możesz pracować nad przestarzałym dokumentem, więc po zapisaniu zmiany, które nastąpiły po etapie pobierania, zostały utracone. –

+2

@What Brickner to typowy przepływ pracy, który polega na zawijaniu logiki w pętlę retry: (Retryable zawiera pobieranie, modyfikowanie, zapisywanie). Jeśli wrócisz do wersji VersionError (wyjątek blokady optymistycznej), możesz ponownie spróbować tej operacji kilka razy i pobrać za każdym razem nową kopię. Wciąż jednak wolę aktualizacje atomowe, jeśli to możliwe! –