MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Pourquoi Mongoose a-t-il à la fois des schémas et des modèles ?

MODIF : Bien que cela ait été utile pour de nombreuses personnes, comme mentionné dans les commentaires, cela répond au "comment" plutôt qu'au pourquoi. Heureusement, le pourquoi de la question a également été répondu ailleurs, avec cette réponse à une autre question. Cela a été lié dans les commentaires depuis un certain temps, mais je me rends compte que beaucoup peuvent ne pas aller aussi loin lors de la lecture.

Souvent, la façon la plus simple de répondre à ce type de question est de donner un exemple. Dans ce cas, quelqu'un l'a déjà fait pour moi :)

Jetez un œil ici :

http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/

MODIF : Le message original (comme mentionné dans les commentaires) semble ne plus exister, je le reproduis donc ci-dessous. S'il revient un jour ou s'il vient de déménager, veuillez m'en informer.

Il donne une description décente de l'utilisation de schémas dans des modèles de mangouste et pourquoi vous voudriez le faire, et vous montre également comment pousser des tâches via le modèle alors que le schéma concerne la structure, etc.

Message d'origine :

Commençons par un exemple simple d'intégration d'un schéma dans un modèle.

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'});

J'ai créé un nouveau TaskSchema objet avec des informations de base qu'une tâche pourrait avoir. Un attribut virtuel Mongoose est configuré pour combiner de manière pratique le nom et la priorité de la tâche. J'ai seulement spécifié un getter ici, mais les setters virtuels sont également pris en charge.

J'ai également défini une méthode de tâche simple appelée isHighPriority pour montrer comment les méthodes fonctionnent avec cette configuration.

Dans le ListSchema définition, vous remarquerez comment les tasks key est configuré pour contenir un tableau de TaskSchema objets. La task key deviendra une instance de DocumentArray qui fournit des méthodes spéciales pour traiter les documents Mongo intégrés.

Pour l'instant je n'ai passé que le ListSchema objet dans mongoose.model et laissé le TaskSchema dehors. Techniquement, il n'est pas nécessaire de tourner le TaskSchema dans un modèle formel puisque nous ne l'enregistrerons pas dans sa propre collection. Plus tard, je vous montrerai comment cela ne nuit à rien si vous le faites et cela peut aider à organiser tous vos modèles de la même manière, surtout lorsqu'ils commencent à s'étendre sur plusieurs fichiers.

Avec la List configuration du modèle, ajoutons-y quelques tâches et enregistrons-les dans 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'); 
    }
});

L'attribut des tâches sur l'instance de notre List modèle (sampleList ) fonctionne comme un tableau JavaScript normal et nous pouvons y ajouter de nouvelles tâches en utilisant push. La chose importante à noter est les tasks sont ajoutés en tant qu'objets JavaScript normaux. C'est une distinction subtile qui peut ne pas être immédiatement intuitive.

Vous pouvez vérifier à partir du shell Mongo que la nouvelle liste et les nouvelles tâches ont été enregistrées dans 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" }

Nous pouvons maintenant utiliser le ObjectId pour afficher la Sample List et parcourir ses tâches.

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());
    });
});

Si vous exécutez ce dernier morceau de code, vous obtiendrez une erreur indiquant que le document intégré n'a pas de méthode isHighPriority . Dans la version actuelle de Mongoose, vous ne pouvez pas accéder directement aux méthodes sur les schémas intégrés. Il existe un ticket ouvert pour résoudre ce problème et après avoir posé la question au groupe Google Mongoose, manimal45 a publié une solution de contournement utile à utiliser pour le moment.

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));
    });
});

Si vous exécutez ce code, vous devriez voir la sortie suivante sur la ligne de commande.

Sample List retrieved
task one
task one (1)
true
task two
task two (5)
false

Avec cette solution de contournement à l'esprit, transformons le TaskSchema dans un modèle 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');

Le TaskSchema la définition est la même qu'avant donc je l'ai laissé de côté. Une fois transformé en modèle, nous pouvons toujours accéder à son objet Schema sous-jacent en utilisant la notation par points.

Créons une nouvelle liste et intégrons-y deux instances de modèle de tâche.

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'); 
    }
});

Comme nous intégrons les instances du modèle de tâche dans la liste, nous appelons toObject sur eux pour convertir leurs données en objets JavaScript simples que le List.tasks DocumentArray attend. Lorsque vous enregistrez des instances de modèle de cette manière, vos documents intégrés contiendront ObjectIds .

L'exemple de code complet est disponible sous forme d'essentiel. Espérons que ces solutions de contournement contribuent à lisser les choses à mesure que Mongoose continue de se développer. Je suis encore assez nouveau sur Mongoose et MongoDB, alors n'hésitez pas à partager de meilleures solutions et astuces dans les commentaires. Bonne modélisation des données !