Być może nadszedł czas, może to ja tonę w rzadkiej dokumentacji i nie jestem w stanie owinąć głowy koncepcją aktualizacji w Mongoose :)
Oto oferta:
Mam schemat i model kontaktu (skrócone właściwości):
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var mongooseTypes = require("mongoose-types"),
useTimestamps = mongooseTypes.useTimestamps;
var ContactSchema = new Schema({
phone: {
type: String,
index: {
unique: true,
dropDups: true
}
},
status: {
type: String,
lowercase: true,
trim: true,
default: 'on'
}
});
ContactSchema.plugin(useTimestamps);
var Contact = mongoose.model('Contact', ContactSchema);
Otrzymuję żądanie od klienta, zawierające pola, których potrzebuję i w ten sposób używam mojego modelu:
mongoose.connect(connectionString);
var contact = new Contact({
phone: request.phone,
status: request.status
});
A teraz dochodzimy do problemu:
- Jeśli zadzwonię
contact.save(function(err){...})
, otrzymam błąd, jeśli kontakt z tym samym numerem telefonu już istnieje (zgodnie z oczekiwaniami - niepowtarzalny) - Nie mogę zadzwonić
update()
na kontakt, ponieważ ta metoda nie istnieje w dokumencie - Jeśli wywołam aktualizację na modelu:
Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
dostanę się do nieskończonej pętli, ponieważ implementacja aktualizacji Mongoose wyraźnie nie chce, aby obiekt był drugim parametrem. - Jeśli zrobię to samo, ale w drugim parametrze przekażę tablicę asocjacyjną właściwości żądania,
{status: request.status, phone: request.phone ...}
to działa - ale wtedy nie mam odniesienia do konkretnego kontaktu i nie mogę znaleźć jegocreatedAt
iupdatedAt
właściwości.
Więc w końcu, po wszystkim, co próbowałem: biorąc pod uwagę dokument contact
, jak go zaktualizować, jeśli istnieje, lub dodać, jeśli nie istnieje?
Dziękuję za Twój czas.
javascript
mongodb
node.js
mongoose
Podróżujący facet techniczny
źródło
źródło
pre
zasave
?Odpowiedzi:
Mongoose obsługuje to teraz natywnie z findOneAndUpdate (wywołuje MongoDB findAndModify ).
Opcja upsert = true tworzy obiekt, jeśli nie istnieje. domyślnie false .
W starszych wersjach Mongoose nie obsługuje tych haków przy użyciu tej metody:
źródło
Właśnie spaliłem solidne 3 godziny, próbując rozwiązać ten sam problem. W szczególności chciałem „zastąpić” cały dokument, jeśli istnieje, lub wstawić go w inny sposób. Oto rozwiązanie:
Utworzyłem problem na stronie projektu Mongoose z prośbą o dodanie informacji o tym do dokumentacji.
źródło
MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn);
MyModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, fn);
Byliście blisko
ale twoim drugim parametrem powinien być na przykład obiekt z operatorem modyfikacji
źródło
{$set: ... }
części, ponieważ jest to automatyczna forma mojego czytaniaCóż, czekałem wystarczająco długo i bez odpowiedzi. W końcu zrezygnowałem z całego podejścia do aktualizacji / aktualizacji i wybrałem:
Czy to działa? Tak. Czy jestem z tego zadowolony? Prawdopodobnie nie. 2 połączenia DB zamiast jednego.
Mamy nadzieję, że przyszłe wdrożenie Mongoose przyniesie jakąś
Model.upsert
funkcję.źródło
runValidators: true
podczas aktualizacji: aktualizuj dokumenty (jednak aktualizatory działają tylko$set
i$unset
działają).upsert()
być dostępny we wszystkich modelach. stackoverflow.com/a/50208331/1586406Bardzo eleganckie rozwiązanie, które można osiągnąć za pomocą łańcucha obietnic:
źródło
(model) => { return model.save(); }
jakomodel => model.save()
, a także(err) => { res.send(err); }
jakoerr => res.send(err)
;)Jestem opiekunem Mongoose. Bardziej nowoczesnym sposobem na zachowanie dokumentu jest użycie tej
Model.updateOne()
funkcji .Jeśli potrzebujesz zaktualizowanego dokumentu, możesz użyć
Model.findOneAndUpdate()
Kluczową kwestią jest to, że musisz umieścić unikalne właściwości
filter
parametru w parametrzeupdateOne()
lubfindOneAndUpdate()
, a pozostałe właściwościupdate
parametru.Oto samouczek dotyczący wstawiania dokumentów w Mongoose .
źródło
Utworzyłem konto StackOverflow, aby odpowiedzieć na to pytanie. Po bezowocnych poszukiwaniach między sieciami sam coś napisałem. Tak to zrobiłem, aby można go było zastosować do dowolnego modelu mangusty. Zaimportuj tę funkcję lub dodaj ją bezpośrednio do kodu, w którym przeprowadzasz aktualizację.
Następnie, aby wstawić dokument mangusty, wykonaj następujące czynności:
To rozwiązanie może wymagać 2 połączeń DB, jednak zyskujesz,
Pamiętaj tylko, że obiekt docelowy zawsze nadpisuje źródło, nawet jeśli źródło ma istniejącą wartość
Ponadto w przypadku tablic, jeśli istniejący obiekt ma dłuższą tablicę niż ta, która ją zastępuje, wówczas wartości na końcu starej tablicy pozostaną. Prostym sposobem na upsertowanie całej tablicy jest ustawienie starej tablicy na pustą tablicę przed upsertem, jeśli to właśnie zamierzasz zrobić.
AKTUALIZACJA - 16.01.2016 Dodałem dodatkowy warunek, jeśli istnieje tablica prymitywnych wartości, Mongoose nie zdaje sobie sprawy, że tablica zostanie zaktualizowana bez użycia funkcji „set”.
źródło
if(_.isObject(value) && _.keys(value).length !== 0) {
warunek ochronny, aby zatrzymać przepełnienie stosu. Tutaj Lodash 4+ wydaje się przekształcać wartości nieobiektywne w obiekty wkeys
wywołaniu, więc ochrona rekurencyjna była zawsze prawdziwa. Może jest lepszy sposób, ale teraz prawie dla mnie działa ...Musiałem zaktualizować / wstawić dokument do jednej kolekcji, a ja stworzyłem nowy literał obiektu, taki jak ten:
składa się z danych, które otrzymuję z innej bazy danych, a następnie wywołuje aktualizację na modelu
to jest wyjście, które otrzymuję po pierwszym uruchomieniu skryptu:
Oto wynik, gdy uruchamiam skrypt po raz drugi:
Używam wersji mangusty 3.6.16
źródło
Oto lepsze podejście do rozwiązania metody aktualizacji w wersji mangoose , możesz sprawdzić Scotch.io, aby uzyskać więcej informacji. To zdecydowanie działało dla mnie !!!
źródło
W wersji 2.6 wprowadzono błąd, który dotyczy również wersji 2.7
Upsert działał poprawnie na 2.4
https://groups.google.com/forum/#!topic/mongodb-user/UcKvx4p4hnY https://jira.mongodb.org/browse/SERVER-13843
Spójrz, zawiera kilka ważnych informacji
AKTUALIZACJA:
To nie znaczy, że upsert nie działa. Oto dobry przykład tego, jak z niego korzystać:
źródło
Możesz po prostu zaktualizować ten rekord i uzyskać zaktualizowane dane w odpowiedzi
źródło
to zadziałało dla mnie.
źródło
Oto najprostszy sposób na utworzenie / aktualizację przy jednoczesnym wywołaniu oprogramowania pośredniego i walidatorów.
źródło
Dla każdego, kto tu przyjeżdża, wciąż szukając dobrego rozwiązania dla „upsertingu” z obsługą haków, właśnie to przetestowałem i działałem. Nadal wymaga 2 połączeń DB, ale jest znacznie bardziej stabilny niż cokolwiek, co próbowałem podczas jednego połączenia.
źródło
Jeśli dostępne są generatory, staje się to jeszcze łatwiejsze:
źródło
Żadne inne rozwiązanie nie działało dla mnie. Korzystam z żądania postu i aktualizuję dane, jeśli znalazłem, wstaw je, a także _id jest wysyłany z treścią żądania, które należy usunąć.
źródło
źródło
źródło
Zgodnie z odpowiedzią Traveling Tech Guy , która już jest niesamowita, możemy stworzyć wtyczkę i dołączyć ją do mangusty po jej zainicjowaniu, aby
.upsert()
była dostępna we wszystkich modelach.plugins.js
db.js
Następnie możesz zrobić coś takiego
User.upsert({ _id: 1 }, { foo: 'bar' })
lubYouModel.upsert({ bar: 'foo' }, { value: 1 })
kiedy chcesz.źródło
Właśnie wróciłem do tego problemu i postanowiłem opublikować wtyczkę na podstawie odpowiedzi Aarona Masta.
https://www.npmjs.com/package/mongoose-recursive-upsert
Użyj go jako wtyczki mangusty. Ustawia metodę statyczną, która rekurencyjnie scali przekazany obiekt.
źródło
Ten skrypt do kawy działa dla mnie z Węzłem - sztuczka polega na tym, że _id pobiera z opakowania ObjectID po wysłaniu i zwróceniu od klienta, więc należy go wymienić na aktualizacje (gdy nie podano _id, save powróci do wstawiania i dodawania jeden).
źródło
na podstawie tego, co napisał Martin Kuzdowicz powyżej. Korzystam z poniższych, aby wykonać aktualizację za pomocą mangusty i głębokiego scalenia obiektów json. Wraz z funkcją model.save () w mongoose pozwala to mangusty wykonać pełną walidację, nawet taką, która opiera się na innych wartościach w json. wymaga pakietu Deepmerge https://www.npmjs.com/package/deepmerge . Ale to bardzo lekki pakiet.
źródło
req.body
w obecnym stanie przed przetestowaniem pod kątem wstrzykiwania NoSQL (patrz owasp.org/index.php/Testing_for_NoSQL_injection ).Po przeczytaniu powyższych postów postanowiłem użyć tego kodu:
jeśli r ma wartość null, tworzymy nowy element. W przeciwnym razie użyj aktualizacji w aktualizacji, ponieważ aktualizacja nie tworzy nowego elementu.
źródło