EDITAR: Embora isso tenha sido útil para muitas pessoas, como mencionado nos comentários, responde ao "como" e não ao porquê. Felizmente, o porquê da pergunta também foi respondido em outro lugar, com esta resposta para outra pergunta. Isso tem sido linkado nos comentários há algum tempo, mas percebo que muitos podem não chegar tão longe ao ler.
Muitas vezes, a maneira mais fácil de responder a esse tipo de pergunta é com um exemplo. Neste caso, alguém já fez isso por mim :)
Dê uma olhada aqui:
http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/
EDITAR: O post original (como mencionado nos comentários) parece não existir mais, então estou reproduzindo-o abaixo. Caso volte, ou se acabou de se mudar, por favor me avise.
Ele fornece uma descrição decente do uso de esquemas dentro de modelos no mangusto e por que você gostaria de fazê-lo, e também mostra como enviar tarefas por meio do modelo enquanto o esquema é sobre a estrutura etc.
Post original:
Vamos começar com um exemplo simples de incorporação de um esquema dentro de um 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'});
Criei um novo
TaskSchema
objeto com informações básicas que uma tarefa pode ter. Um atributo virtual do Mongoose é configurado para combinar convenientemente o nome e a prioridade da Tarefa. Eu apenas especifiquei um getter aqui, mas os setters virtuais também são suportados. Também defini um método de tarefa simples chamado
isHighPriority
para demonstrar como os métodos funcionam com essa configuração. No
ListSchema
definição, você notará como as tasks
key está configurada para conter uma matriz de TaskSchema
objetos. A task
key se tornará uma instância de DocumentArray
que fornece métodos especiais para lidar com documentos Mongo incorporados. Por enquanto só passei o
ListSchema
objeto em mongoose.model
e deixou o TaskSchema
Fora. Tecnicamente, não é necessário ativar o TaskSchema
em um modelo formal, pois não o salvaremos em sua própria coleção. Mais tarde, mostrarei como isso não prejudica nada se você fizer isso e pode ajudar a organizar todos os seus modelos da mesma maneira, especialmente quando eles começam a abranger vários arquivos. Com a
List
configuração do modelo, vamos adicionar algumas tarefas a ele e salvá-las no 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');
}
});
O atributo tasks na instância de nossa
List
model (sampleList
) funciona como um array JavaScript regular e podemos adicionar novas tarefas a ele usando push. O importante a observar são as tasks
são adicionados como objetos JavaScript regulares. É uma distinção sutil que pode não ser imediatamente intuitiva. Você pode verificar no shell do Mongo se a nova lista e as tarefas foram salvas no 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" }
Agora podemos usar o
ObjectId
para abrir a Sample List
e iterar através de suas tarefas. 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 você executar esse último pedaço de código, receberá um erro informando que o documento incorporado não possui um método
isHighPriority
. Na versão atual do Mongoose, você não pode acessar métodos em esquemas incorporados diretamente. Há um ticket aberto para corrigi-lo e, depois de fazer a pergunta ao Mongoose Google Group, manimal45 postou uma solução útil para usar por enquanto. 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 você executar esse código, deverá ver a seguinte saída na linha de comando.
Sample List retrieved
task one
task one (1)
true
task two
task two (5)
false
Com essa solução alternativa em mente, vamos transformar o
TaskSchema
em um modelo 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');
O
TaskSchema
definição é a mesma de antes, então eu deixei de fora. Uma vez transformado em um modelo, ainda podemos acessar seu objeto Schema subjacente usando a notação de ponto. Vamos criar uma nova lista e incorporar duas instâncias do modelo Task nela.
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');
}
});
Conforme estamos incorporando as instâncias do modelo Task na List, estamos chamando
toObject
neles para converter seus dados em objetos JavaScript simples que o List.tasks
DocumentArray
está esperando. Ao salvar instâncias de modelo dessa forma, seus documentos incorporados conterão ObjectIds
. O exemplo de código completo está disponível como uma essência. Espero que essas soluções alternativas ajudem a suavizar as coisas à medida que o Mongoose continua a se desenvolver. Ainda sou muito novo no Mongoose e no MongoDB, então sinta-se à vontade para compartilhar melhores soluções e dicas nos comentários. Boa modelagem de dados!