Te dwa typy obiektów wydają się być tak blisko siebie, że posiadanie obu wydaje się zbędne. Jaki jest sens posiadania zarówno schematów, jak i modeli?
Te dwa typy obiektów wydają się być tak blisko siebie, że posiadanie obu wydaje się zbędne. Jaki jest sens posiadania zarówno schematów, jak i modeli?
Odpowiedzi:
Często najłatwiejszym sposobem odpowiedzi na tego typu pytania jest podanie przykładu. W takim razie ktoś już to za mnie zrobił :)
Spójrz tutaj:
http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/
EDYCJA: Oryginalny post (jak wspomniano w komentarzach) wydaje się już nie istnieć, więc powielam go poniżej. Jeśli kiedykolwiek wróci lub właśnie się poruszył, daj mi znać.
Daje przyzwoity opis korzystania ze schematów w modelach w mangusta i dlaczego chciałbyś to zrobić, a także pokazuje, jak przesuwać zadania za pośrednictwem modelu, podczas gdy schemat dotyczy struktury itp.
Oryginalny post:
Zacznijmy od prostego przykładu osadzania schematu wewnątrz modelu.
var TaskSchema = new Schema({
name: String,
priority: Number
});
TaskSchema.virtual('nameandpriority')
.get( function () {
return this.name + '(' + this.priority + ')';
});
TaskSchema.method('isHighPriority', function() {
if(this.priority === 1) {
return true;
} else {
return false;
}
});
var ListSchema = new Schema({
name: String,
tasks: [TaskSchema]
});
mongoose.model('List', ListSchema);
var List = mongoose.model('List');
var sampleList = new List({name:'Sample List'});
Utworzyłem nowy TaskSchema
obiekt z podstawowymi informacjami, które może mieć zadanie. Wirtualny atrybut Mongoose jest skonfigurowany tak, aby wygodnie łączyć nazwę i priorytet zadania. Podałem tutaj tylko metodę pobierającą, ale obsługiwane są również metody ustawiające wirtualne.
Zdefiniowałem również prostą metodę zadaniową o nazwie, isHighPriority
aby zademonstrować, jak działają metody w tej konfiguracji.
W ListSchema
definicji zauważysz, jak klucz zadań jest skonfigurowany do przechowywania tablicy TaskSchema
obiektów. Klucz zadania stanie się instancją, DocumentArray
która zapewnia specjalne metody radzenia sobie z osadzonymi dokumentami Mongo.
Na razie przekazałem ListSchema
obiekt tylko do mongoose.model i zostawiłem TaskSchema wyłączony. Technicznie nie jest konieczne przekształcanie go TaskSchema
w model formalny, ponieważ nie będziemy go zapisywać w jego własnej kolekcji. Później pokażę ci, jak nic nie szkodzi, jeśli to zrobisz, i może pomóc uporządkować wszystkie modele w ten sam sposób, zwłaszcza gdy zaczynają obejmować wiele plików.
Przy List
konfiguracji modelu dodajmy do niego kilka zadań i zapiszmy je w Mongo.
var List = mongoose.model('List');
var sampleList = new List({name:'Sample List'});
sampleList.tasks.push(
{name:'task one', priority:1},
{name:'task two', priority:5}
);
sampleList.save(function(err) {
if (err) {
console.log('error adding new list');
console.log(err);
} else {
console.log('new list successfully saved');
}
});
Atrybut zadań na instancji naszego List
modelu ( simpleList
) działa jak zwykła tablica JavaScript i możemy dodawać do niego nowe zadania za pomocą metody push. Należy zwrócić uwagę na to, że zadania są dodawane jako zwykłe obiekty JavaScript. To subtelne rozróżnienie, które może nie być od razu intuicyjne.
Możesz sprawdzić z powłoki Mongo, że nowa lista i zadania zostały zapisane w mongo.
db.lists.find()
{ "tasks" : [
{
"_id" : ObjectId("4dd1cbeed77909f507000002"),
"priority" : 1,
"name" : "task one"
},
{
"_id" : ObjectId("4dd1cbeed77909f507000003"),
"priority" : 5,
"name" : "task two"
}
], "_id" : ObjectId("4dd1cbeed77909f507000001"), "name" : "Sample List" }
Teraz możemy użyć ObjectId
do wyciągnięcia Sample List
i iteracji przez jego zadania.
List.findById('4dd1cbeed77909f507000001', function(err, list) {
console.log(list.name + ' retrieved');
list.tasks.forEach(function(task, index, array) {
console.log(task.name);
console.log(task.nameandpriority);
console.log(task.isHighPriority());
});
});
Jeśli uruchomisz ten ostatni fragment kodu, pojawi się błąd informujący, że osadzony dokument nie ma metody isHighPriority
. W aktualnej wersji Mongoose nie ma bezpośredniego dostępu do metod w osadzonych schematach. Jest otwarte zgłoszenie, aby to naprawić, a po zadaniu pytania Mongoose Google Group, manimal45 opublikował pomocne obejście do teraz.
List.findById('4dd1cbeed77909f507000001', function(err, list) {
console.log(list.name + ' retrieved');
list.tasks.forEach(function(task, index, array) {
console.log(task.name);
console.log(task.nameandpriority);
console.log(task._schema.methods.isHighPriority.apply(task));
});
});
Jeśli uruchomisz ten kod, powinieneś zobaczyć następujące dane wyjściowe w wierszu poleceń.
Sample List retrieved
task one
task one (1)
true
task two
task two (5)
false
Mając to na uwadze, przejdźmy TaskSchema
do modelu Mongoose.
mongoose.model('Task', TaskSchema);
var Task = mongoose.model('Task');
var ListSchema = new Schema({
name: String,
tasks: [Task.schema]
});
mongoose.model('List', ListSchema);
var List = mongoose.model('List');
TaskSchema
Definicja jest taka sama jak wcześniej, więc zostawiłem ją. Po przekształceniu go w model nadal możemy uzyskać dostęp do jego podstawowego obiektu Schema za pomocą notacji kropkowej.
Utwórzmy nową listę i umieśćmy w niej dwie instancje modelu zadań.
var demoList = new List({name:'Demo List'});
var taskThree = new Task({name:'task three', priority:10});
var taskFour = new Task({name:'task four', priority:11});
demoList.tasks.push(taskThree.toObject(), taskFour.toObject());
demoList.save(function(err) {
if (err) {
console.log('error adding new list');
console.log(err);
} else {
console.log('new list successfully saved');
}
});
Gdy osadzamy instancje modelu zadania na liście, wzywamy toObject
je do konwersji ich danych na zwykłe obiekty JavaScript, których List.tasks
DocumentArray
oczekuje. Gdy zapiszesz instancje modelu w ten sposób, twoje osadzone dokumenty będą zawierały ObjectIds
.
Pełny przykład kodu jest dostępny jako streszczenie . Mam nadzieję, że te obejścia pomogą załagodzić sytuację, ponieważ Mongoose nadal się rozwija. Wciąż jestem całkiem nowy w Mongoose i MongoDB, więc zachęcam do dzielenia się lepszymi rozwiązaniami i wskazówkami w komentarzach. Miłego modelowania danych!
Schemat to obiekt, który definiuje strukturę wszystkich dokumentów, które będą przechowywane w kolekcji MongoDB; umożliwia definiowanie typów i walidatorów dla wszystkich elementów danych.
Model to obiekt, który zapewnia łatwy dostęp do nazwanej kolekcji, umożliwiając wysyłanie zapytań do kolekcji i używanie schematu do walidacji dokumentów zapisywanych w tej kolekcji. Jest tworzony przez połączenie schematu, połączenia i nazwy kolekcji.
Pierwotnie sformułowane przez Valeri Karpov, blog MongoDB
Nie sądzę, aby zaakceptowana odpowiedź faktycznie odpowiadała na postawione pytanie. Odpowiedź nie wyjaśnia, dlaczego Mongoose zdecydował się wymagać od programisty dostarczenia zarówno schematu, jak i zmiennej modelu. Przykład frameworka, w którym wyeliminowano potrzebę deweloperaDo zdefiniowania schematu danych służy django - programista zapisuje swoje modele w pliku models.py i pozostawia to frameworkowi w celu zarządzania schematem. Pierwszym powodem, dla którego to robią, biorąc pod uwagę moje doświadczenie z django, jest łatwość użycia. Może ważniejsza jest zasada DRY (nie powtarzaj się) - nie musisz pamiętać o aktualizowaniu schematu przy zmianie modelu - django zrobi to za Ciebie! Railsy zarządzają również schematem danych za Ciebie - programista nie edytuje schematu bezpośrednio, ale zmienia go, definiując migracje, które manipulują schematem.
Jednym z powodów, dla których mogłem zrozumieć, że Mongoose oddzieliłby schemat od modelu, są przypadki, w których chciałbyś zbudować model z dwóch schematów. Taki scenariusz może wprowadzić więcej złożoności, niż warto zarządzać - jeśli masz dwa schematy zarządzane przez jeden model, dlaczego nie są one jednym schematem?
Być może pierwotne pytanie jest raczej reliktem tradycyjnego systemu relacyjnych baz danych. W świecie NoSQL / Mongo być może schemat jest nieco bardziej elastyczny niż MySQL / PostgreSQL, a zatem zmiana schematu jest bardziej powszechną praktyką.
Zrozumieć dlaczego? musisz zrozumieć, czym właściwie jest Mongoose?
Cóż, mangusta to biblioteka do modelowania danych obiektowych dla MongoDB i Node JS, zapewniająca wyższy poziom abstrakcji. Jest to więc trochę jak relacja między Express i Node, więc Express jest warstwą abstrakcji nad zwykłym Node, podczas gdy Mongoose jest warstwą abstrakcji nad zwykłym sterownikiem MongoDB.
Biblioteka modelowania danych obiektowych jest dla nas tylko sposobem na napisanie kodu JavaScript, który będzie następnie współdziałać z bazą danych. Więc moglibyśmy po prostu użyć zwykłego sterownika MongoDB, aby uzyskać dostęp do naszej bazy danych, działałoby dobrze.
Ale zamiast tego używamy Mongoose, ponieważ zapewnia nam o wiele więcej funkcjonalności po wyjęciu z pudełka, umożliwiając szybsze i prostsze tworzenie naszych aplikacji.
Tak więc niektóre funkcje Mongoose daje nam schematy do modelowania naszych danych i relacji, łatwą weryfikację danych, proste API zapytań, oprogramowanie pośredniczące i wiele więcej.
W Mongoose schemat to miejsce, w którym modelujemy nasze dane, opisujemy strukturę danych, wartości domyślne i walidację, a następnie bierzemy ten schemat i tworzymy z niego model, model jest w zasadzie opakowaniem wokół schematu, co pozwala nam faktycznie komunikować się z bazą danych w celu tworzenia, usuwania, aktualizowania i czytania dokumentów.
Stwórzmy model ze schematu.
const tourSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'A tour must have a name'],
unique: true,
},
rating: {
type: Number,
default: 4.5,
},
price: {
type: Number,
required: [true, 'A tour must have a price'],
},
});
//tour model
const Tour = mongoose.model('Tour', tourSchema);
Zgodnie z umową pierwsza litera nazwy modelu musi być wielka.
Stwórzmy instancję naszego modelu, który stworzyliśmy przy użyciu mongoose i schematu. również wchodź w interakcję z naszą bazą danych.
const testTour = new Tour({ // instance of our model
name: 'The Forest Hiker',
rating: 4.7,
price: 497,
});
// saving testTour document into database
testTour
.save()
.then((doc) => {
console.log(doc);
})
.catch((err) => {
console.log(err);
});
Tak więc posiadanie zarówno schamy, jak i modle mangusty ułatwia nam życie.