EDYTUJ: Chociaż było to przydatne dla wielu osób, jak wspomniano w komentarzach, odpowiada raczej „jak”, a nie dlaczego. Na szczęście odpowiedź na pytanie została udzielona również w innym miejscu, z tą odpowiedzią na inne pytanie. Zostało to od pewnego czasu połączone w komentarzach, ale zdaję sobie sprawę, że wielu może nie zajść tak daleko podczas czytania.
Często najłatwiejszym sposobem odpowiedzi na tego typu pytanie jest podanie przykładu. W tym przypadku ktoś już to za mnie zrobił :)
Spójrz tutaj:
http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/
EDYTUJ: Oryginalny post (jak wspomniano w komentarzach) wydaje się już nie istnieć, więc odtwarzam go poniżej. Jeśli kiedykolwiek wróci lub właśnie się przeniósł, daj mi znać.
Daje przyzwoity opis używania schematów w modelach w manguście i dlaczego chcesz to zrobić, a także pokazuje, jak przekazywać zadania przez model, podczas gdy schemat dotyczy całej struktury itp.
Oryginalny post:
Zacznijmy od prostego przykładu osadzenia schematu w 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, jakie może mieć zadanie. Atrybut wirtualny Mongoose jest skonfigurowany tak, aby wygodnie łączyć nazwę i priorytet zadania. Określiłem tutaj tylko getter, ale obsługiwane są również wirtualne setery.
Zdefiniowałem również prostą metodę zadania o nazwie isHighPriority
aby zademonstrować, jak metody działają z tą konfiguracją.
W ListSchema
definicję zauważysz, jak tasks
klucz jest skonfigurowany do przechowywania tablicy TaskSchema
przedmioty. task
klucz stanie się instancją DocumentArray
który zapewnia specjalne metody radzenia sobie z osadzonymi dokumentami Mongo.
Na razie przekazałem tylko ListSchema
obiekt do mongoose.model
i opuścił TaskSchema
na zewnątrz. Z technicznego punktu widzenia nie jest konieczne włączanie TaskSchema
w formalny model, ponieważ nie będziemy go przechowywać w jego własnej kolekcji. Później pokażę ci, jak to niczego nie zaszkodzi, jeśli to zrobisz, i może pomóc uporządkować wszystkie modele w ten sam sposób, zwłaszcza gdy zaczynają one obejmować wiele plików.
Z List
konfiguracja 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ń w wystąpieniu naszej List
model (sampleList
) działa jak zwykła tablica JavaScript i możemy dodawać do niej nowe zadania za pomocą push. Ważną rzeczą do zauważenia są tasks
są dodawane jako zwykłe obiekty JavaScript. To subtelne rozróżnienie, które może nie być od razu intuicyjne.
Możesz sprawdzić w powłoce 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
aby wyświetlić Sample List
i powtarzaj swoje 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 obecnej wersji Mongoose nie masz bezpośredniego dostępu do metod na osadzonych schematach. Istnieje otwarte zgłoszenie, aby to naprawić, a po zadaniu pytania grupie dyskusyjnej Mongoose, manimal45 opublikował przydatne obejście problemu, z którego można skorzystać na razie.
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, zmieńmy TaskSchema
w model 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 ją pominąłem. Po przekształceniu w model nadal możemy uzyskać dostęp do podstawowego obiektu Schema za pomocą notacji kropkowej.
Utwórzmy nową listę i osadź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');
}
});
Ponieważ osadzamy instancje modelu zadań na liście, wywołujemy toObject
na nich, aby przekonwertować ich dane na zwykłe obiekty JavaScript, które List.tasks
DocumentArray
oczekuje. Gdy zapiszesz instancje modelu w ten sposób, Twoje osadzone dokumenty będą zawierać ObjectIds
.
Pełny przykład kodu jest dostępny jako sedno. Mam nadzieję, że te obejścia pomogą wygładzić sytuację, gdy Mongoose nadal się rozwija. Nadal 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!