BEARBEITEN: Obwohl dies für viele Menschen nützlich war, beantwortet es, wie in den Kommentaren erwähnt, eher das „Wie“ als das Warum. Zum Glück wurde das Warum der Frage auch an anderer Stelle beantwortet, mit dieser Antwort auf eine andere Frage. Das wird schon länger in den Kommentaren verlinkt, aber mir ist klar, dass viele beim Lesen vielleicht nicht so weit kommen.
Oft lässt sich diese Art von Frage am einfachsten anhand eines Beispiels beantworten. In diesem Fall hat es schon jemand für mich getan :)
Schau mal hier:
http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/
BEARBEITEN: Der ursprüngliche Beitrag (wie in den Kommentaren erwähnt) scheint nicht mehr zu existieren, daher reproduziere ich ihn unten. Sollte es jemals zurückkehren oder gerade umgezogen sein, lassen Sie es mich bitte wissen.
Es gibt eine anständige Beschreibung der Verwendung von Schemas innerhalb von Modellen in Mongoose und warum Sie dies tun möchten, und zeigt Ihnen auch, wie Sie Aufgaben über das Modell übertragen, während sich das Schema nur um die Struktur usw. dreht.
Ursprünglicher Beitrag:
Beginnen wir mit einem einfachen Beispiel für das Einbetten eines Schemas in ein Modell.
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'});
Ich habe ein neues TaskSchema
erstellt Objekt mit grundlegenden Informationen, die eine Aufgabe haben könnte. Ein virtuelles Mongoose-Attribut wird eingerichtet, um den Namen und die Priorität der Aufgabe bequem zu kombinieren. Ich habe hier nur einen Getter angegeben, aber virtuelle Setter werden ebenfalls unterstützt.
Ich habe auch eine einfache Aufgabenmethode namens isHighPriority
definiert um zu demonstrieren, wie Methoden mit diesem Setup funktionieren.
Im ListSchema
Definition werden Sie feststellen, wie die tasks
key ist so konfiguriert, dass er ein Array von TaskSchema
enthält Objekte. Die task
key wird zu einer Instanz von DocumentArray
die spezielle Methoden für den Umgang mit eingebetteten Mongo-Dokumenten bereitstellt.
Im Moment habe ich nur das ListSchema
übergeben Objekt in mongoose.model
und verließ das TaskSchema
aus. Technisch ist es nicht notwendig, das TaskSchema
zu drehen in ein formales Modell, da wir es nicht in einer eigenen Sammlung speichern werden. Später werde ich Ihnen zeigen, dass es nichts schadet, wenn Sie es tun, und dass es hilfreich sein kann, alle Ihre Modelle auf die gleiche Weise zu organisieren, insbesondere wenn sie anfangen, sich über mehrere Dateien zu erstrecken.
Mit der List
Modell-Setup fügen wir ein paar Aufgaben hinzu und speichern sie in 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');
}
});
Das Aufgabenattribut auf der Instanz unserer List
Modell (sampleList
) funktioniert wie ein normales JavaScript-Array und wir können ihm per Push neue Aufgaben hinzufügen. Das Wichtigste sind die tasks
werden als reguläre JavaScript-Objekte hinzugefügt. Es ist eine subtile Unterscheidung, die möglicherweise nicht sofort intuitiv ist.
Sie können von der Mongo-Shell aus überprüfen, ob die neue Liste und die Aufgaben in Mongo gespeichert wurden.
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" }
Jetzt können wir die ObjectId
verwenden um die Sample List
aufzurufen und seine Aufgaben durchlaufen.
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());
});
});
Wenn Sie das letzte Bit des Codes ausführen, erhalten Sie eine Fehlermeldung, die besagt, dass das eingebettete Dokument keine Methode isHighPriority
hat . In der aktuellen Version von Mongoose können Sie nicht direkt auf Methoden in eingebetteten Schemas zugreifen. Es gibt ein offenes Ticket, um das Problem zu beheben, und nachdem manimal45 die Frage an die Mongoose Google Group gestellt hat, hat manimal45 eine hilfreiche Problemumgehung gepostet, die vorerst verwendet werden kann.
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));
});
});
Wenn Sie diesen Code ausführen, sollten Sie die folgende Ausgabe auf der Befehlszeile sehen.
Sample List retrieved
task one
task one (1)
true
task two
task two (5)
false
Lassen Sie uns mit dieser Problemumgehung das TaskSchema
ändern in ein Mongoose-Modell.
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');
Das TaskSchema
Die Definition ist die gleiche wie zuvor, also habe ich sie weggelassen. Sobald es in ein Modell umgewandelt wurde, können wir immer noch mit der Punktnotation auf das zugrunde liegende Schema-Objekt zugreifen.
Lassen Sie uns eine neue Liste erstellen und zwei Aufgabenmodellinstanzen darin einbetten.
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');
}
});
Während wir die Aufgabenmodellinstanzen in die Liste einbetten, rufen wir toObject
auf auf ihnen, ihre Daten in einfache JavaScript-Objekte umzuwandeln, die die List.tasks
DocumentArray
erwartet. Wenn Sie Modellinstanzen auf diese Weise speichern, enthalten Ihre eingebetteten Dokumente ObjectIds
.
Das vollständige Codebeispiel ist als Gist verfügbar. Hoffentlich helfen diese Problemumgehungen, die Dinge zu glätten, während sich Mongoose weiterentwickelt. Ich bin immer noch ziemlich neu bei Mongoose und MongoDB, also zögern Sie nicht, bessere Lösungen und Tipps in den Kommentaren zu teilen. Viel Spaß beim Datenmodellieren!