sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Por qué Mongoose tiene tanto esquemas como modelos?

EDITAR: Aunque esto ha sido útil para muchas personas, como se menciona en los comentarios, responde al "cómo" en lugar del por qué. Afortunadamente, el por qué de la pregunta también se ha respondido en otro lugar, con esta respuesta a otra pregunta. Esto se ha vinculado en los comentarios durante algún tiempo, pero me doy cuenta de que muchos pueden no llegar tan lejos al leer.

A menudo, la forma más fácil de responder a este tipo de preguntas es con un ejemplo. En este caso, alguien ya lo ha hecho por mí :)

Echa un vistazo aquí:

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

EDITAR: La publicación original (como se menciona en los comentarios) parece que ya no existe, así que la reproduzco a continuación. Si alguna vez regresa, o si acaba de mudarse, hágamelo saber.

Da una descripción decente del uso de esquemas dentro de modelos en mongoose y por qué querrías hacerlo, y también te muestra cómo enviar tareas a través del modelo mientras que el esquema tiene que ver con la estructura, etc.

Publicación original:

Comencemos con un ejemplo simple de incrustación de un esquema dentro de un modelo.

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

Creé un nuevo TaskSchema objeto con información básica que podría tener una tarea. Se configura un atributo virtual Mongoose para combinar convenientemente el nombre y la prioridad de la tarea. Solo especifiqué un getter aquí, pero también se admiten setters virtuales.

También definí un método de tarea simple llamado isHighPriority para demostrar cómo funcionan los métodos con esta configuración.

En el ListSchema definición notará cómo las tasks la clave está configurada para contener una matriz de TaskSchema objetos. La task key se convertirá en una instancia de DocumentArray que proporciona métodos especiales para tratar con documentos Mongo incrustados.

Por ahora solo pasé el ListSchema objeto en mongoose.model y dejó el TaskSchema afuera. Técnicamente no es necesario convertir el TaskSchema en un modelo formal ya que no lo guardaremos en su propia colección. Más adelante le mostraré cómo no daña nada si lo hace y puede ayudarlo a organizar todos sus modelos de la misma manera, especialmente cuando comienzan a abarcar varios archivos.

Con la List configuración del modelo, agreguemos un par de tareas y guardémoslas en 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'); 
    }
});

El atributo de tareas en la instancia de nuestra List modelo (sampleList ) funciona como una matriz de JavaScript normal y podemos agregarle nuevas tareas usando push. Lo importante a tener en cuenta son las tasks se agregan como objetos regulares de JavaScript. Es una distinción sutil que puede no ser inmediatamente intuitiva.

Puede verificar desde el shell de Mongo que la nueva lista y las tareas se guardaron en 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" }

Ahora podemos usar el ObjectId para abrir la Sample List e iterar a través de sus tareas.

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 ejecuta ese último fragmento de código, obtendrá un error que indica que el documento incrustado no tiene un método isHighPriority . En la versión actual de Mongoose, no puede acceder directamente a métodos en esquemas incrustados. Hay un ticket abierto para solucionarlo y, después de plantear la pregunta al grupo de Google Mongoose, manimal45 publicó una solución útil para usar por ahora.

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 ejecuta ese código, debería ver el siguiente resultado en la línea de comando.

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

Con esa solución en mente, cambiemos el TaskSchema en un modelo de Mangosta.

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

El TaskSchema la definición es la misma que antes, así que la dejé fuera. Una vez que se convierte en un modelo, aún podemos acceder a su objeto de esquema subyacente utilizando la notación de puntos.

Vamos a crear una nueva lista e incrustar dos instancias del modelo de tareas dentro de ella.

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

A medida que incrustamos las instancias del modelo de tareas en la Lista, llamamos a toObject en ellos para convertir sus datos en objetos simples de JavaScript que List.tasks DocumentArray está esperando Cuando guarde instancias de modelo de esta manera, sus documentos incrustados contendrán ObjectIds .

El ejemplo de código completo está disponible como resumen. Esperemos que estas soluciones ayuden a suavizar las cosas a medida que Mongoose continúa desarrollándose. Todavía soy bastante nuevo en Mongoose y MongoDB, así que no dude en compartir mejores soluciones y consejos en los comentarios. ¡Feliz modelado de datos!