MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Warum hat Mongoose sowohl Schemas als auch Modelle?

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!