MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Perché Mongoose ha sia schemi che modelli?

MODIFICA: Anche se questo è stato utile per molte persone, come menzionato nei commenti risponde al "come" piuttosto che al perché. Per fortuna, il perché della domanda è stato risposto anche altrove, con questa risposta a un'altra domanda. Questo è stato collegato nei commenti per un po' di tempo, ma mi rendo conto che molti potrebbero non arrivare così lontano durante la lettura.

Spesso il modo più semplice per rispondere a questo tipo di domanda è con un esempio. In questo caso qualcuno l'ha già fatto per me :)

Dai un'occhiata qui:

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

MODIFICA: Il post originale (come accennato nei commenti) sembra non esistere più, quindi lo riproduco di seguito. Se dovesse tornare, o se si è appena trasferito, faccelo sapere.

Fornisce una descrizione decente dell'utilizzo degli schemi all'interno dei modelli in mangusta e del motivo per cui vorresti farlo, e mostra anche come eseguire il push delle attività tramite il modello mentre lo schema riguarda esclusivamente la struttura, ecc.

Post originale:

Iniziamo con un semplice esempio di incorporamento di uno schema all'interno di un modello.

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

Ho creato un nuovo TaskSchema oggetto con informazioni di base che un'attività potrebbe avere. Un attributo virtuale Mongoose è impostato per combinare convenientemente il nome e la priorità dell'attività. Ho specificato solo un getter qui, ma sono supportati anche i setter virtuali.

Ho anche definito un semplice metodo di attività chiamato isHighPriority per dimostrare come funzionano i metodi con questa configurazione.

In ListSchema definizione noterai come le tasks la chiave è configurata per contenere un array di TaskSchema oggetti. L'task key diventerà un'istanza di DocumentArray che fornisce metodi speciali per gestire i documenti Mongo incorporati.

Per ora ho superato solo il ListSchema oggetto in mongoose.model e ho lasciato TaskSchema fuori. Tecnicamente non è necessario girare il TaskSchema in un modello formale poiché non lo salveremo nella sua collezione. Più avanti ti mostrerò come non nuocere a nulla se lo fai e può aiutare a organizzare tutti i tuoi modelli allo stesso modo, specialmente quando iniziano a estendersi su più file.

Con la List configurazione del modello aggiungiamo un paio di attività e le salviamo su 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'attributo delle attività sull'istanza del nostro List modello (sampleList ) funziona come un normale array JavaScript e possiamo aggiungere nuove attività usando push. La cosa importante da notare sono le task vengono aggiunti come normali oggetti JavaScript. È una sottile distinzione che potrebbe non essere immediatamente intuitiva.

Puoi verificare dalla shell di Mongo che il nuovo elenco e le attività siano stati salvati in 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" }

Ora possiamo usare ObjectId per visualizzare l'Sample List e scorrere le sue attività.

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

Se esegui l'ultimo bit di codice, riceverai un errore che dice che il documento incorporato non ha un metodo isHighPriority . Nella versione corrente di Mongoose non è possibile accedere direttamente ai metodi sugli schemi incorporati. C'è un ticket aperto per risolverlo e dopo aver posto la domanda al Mongoose Google Group, manimal45 ha pubblicato un'utile soluzione alternativa da utilizzare per ora.

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

Se esegui quel codice dovresti vedere il seguente output sulla riga di comando.

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

Con questa soluzione in mente, giriamo il TaskSchema in un modello Mangusta.

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

Lo TaskSchema la definizione è la stessa di prima, quindi l'ho omessa. Una volta trasformato in un modello, possiamo ancora accedere al suo oggetto Schema sottostante usando la notazione del punto.

Creiamo un nuovo elenco e incorporiamo due istanze del modello Task al suo interno.

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

Poiché stiamo incorporando le istanze del modello Task nell'elenco, chiamiamo toObject su di essi per convertire i loro dati in semplici oggetti JavaScript che List.tasks DocumentArray si aspetta. Quando salvi le istanze del modello in questo modo, i tuoi documenti incorporati conterranno ObjectIds .

L'esempio di codice completo è disponibile come sintesi. Si spera che queste soluzioni alternative aiutino ad appianare le cose mentre Mongoose continua a svilupparsi. Sono ancora abbastanza nuovo su Mongoose e MongoDB, quindi sentiti libero di condividere soluzioni e suggerimenti migliori nei commenti. Buona modellazione dei dati!