Esquemas, modelos e virtuais do Mongoose
Você definirá esquemas do Mongoose com tipo, validação e opções padrão, criará modelos e adicionará propriedades virtuais.
Esquemas, modelos e virtuais do Mongoose é uma aula grátis de MongoDB Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de MongoDB Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de MongoDB Academy inclui 4 aulas no total.
O que é o Mongoose
Mongoose é um Mapeador de Documentos de Objetos (ODM) para MongoDB e Node.js. Ele funciona sobre o driver oficial do MongoDB e adiciona uma camada de abstração: esquemas para validar a estrutura dos documentos, modelos para interagir com o banco de dados, ganchos de middleware para a lógica anterior e posterior às operações e virtuais para campos calculados. Mongoose é a biblioteca de MongoDB mais popular do ecossistema Node.js e é especialmente produtivo para aplicações de servidor com modelos de dados bem definidos.
// Install Mongoose
// npm install mongoose
const mongoose = require('mongoose');
// Connect to MongoDB
await mongoose.connect(process.env.MONGODB_URI);
console.log('Mongoose connected to MongoDB');Definindo um Schema
Um Schema do Mongoose define a estrutura, os tipos e as restrições dos documentos de uma coleção. Cada chave do esquema corresponde a um campo do documento. Você pode especificar tipo, obrigatoriedade, valor padrão, mínimo, máximo, enumeração e muitas outras opções de validação por campo. Os esquemas são a única fonte de verdade para a estrutura dos documentos em uma aplicação Mongoose.
const { Schema } = mongoose;
const userSchema = new Schema({
name: {
type: String,
required: [true, 'Name is required'],
trim: true,
maxlength: 100
},
email: {
type: String,
required: true,
unique: true,
lowercase: true // automatically converts to lowercase before saving
},
age: {
type: Number,
min: [0, 'Age cannot be negative'],
max: 150
},
role: {
type: String,
enum: ['admin', 'user', 'guest'],
default: 'user'
},
createdAt: {
type: Date,
default: Date.now
}
});Tipos de Schema: tipos compatíveis
O Mongoose é compatível com um conjunto amplo de tipos de esquema. Os mais comuns são String, Number, Date, Boolean, Buffer, mongoose.Schema.Types.ObjectId (para referências), Array (indicado como [Type]) e Mixed (qualquer valor, sem verificação de tipo). O Mongoose também é compatível com esquemas aninhados (subdocumentos), aninhando uma definição de Schema dentro da definição de campo de outro Schema.
const { Schema } = mongoose;
const { ObjectId } = Schema.Types;
const orderSchema = new Schema({
customerId: { type: ObjectId, ref: 'User', required: true }, // reference to User model
items: [
{
productId: { type: ObjectId, ref: 'Product' },
quantity: { type: Number, min: 1 },
price: Number
}
],
total: Number,
status: { type: String, default: 'pending' },
metadata: Schema.Types.Mixed, // accepts any shape
tags: [String], // array of strings
shippedAt: Date
});Opção de marcas de data e hora
Passar { timestamps: true } como segundo argumento ao construtor de Schema faz com que o Mongoose gerencie automaticamente os campos createdAt e updatedAt em cada documento. createdAt é definido uma vez durante a inserção, e updatedAt é atualizado a cada salvamento. Você não precisa definir esses campos manualmente — o Mongoose cuida deles de forma transparente. Essa é uma prática recomendada para todos os esquemas em produção.
const productSchema = new Schema(
{
name: { type: String, required: true },
price: { type: Number, required: true },
category: String,
stock: { type: Number, default: 0 }
},
{ timestamps: true } // adds createdAt and updatedAt automatically
);
// Documents will have:
// { name: 'Laptop', price: 999, createdAt: Date, updatedAt: Date }Criando um Model
Um Model é um construtor compilado a partir de um Schema. Ele fornece a interface para consultar e gravar documentos na coleção. Chame mongoose.model('ModelName', schema) para criar um modelo — o primeiro argumento é o nome singular da coleção (o Mongoose o transforma automaticamente em plural: “User” → coleção “users”). Os modelos devem ser criados uma vez e exportados como módulos.
// Define schema
const userSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true },
role: { type: String, default: 'user' }
}, { timestamps: true });
// Compile the model
const User = mongoose.model('User', userSchema);
// This creates/uses the 'users' collection
module.exports = User;
// Usage in another file:
// const User = require('./models/user');
// const user = await User.findOne({ email: 'alice@example.com' });Criando documentos com new Model()
Crie uma nova instância de documento usando o construtor do modelo: new User({ name: '...', ... }). Isso cria um objeto de documento em memória com validação, mas NÃO o salva no banco de dados. Chame .save() na instância para persistir o documento ou use a forma abreviada estática User.create(), que combina as duas etapas. O Mongoose valida o documento em relação ao esquema antes de salvá-lo e lança um ValidationError se as restrições forem violadas.
// Method 1: new + save (two-step)
const user = new User({
name: 'Alice',
email: 'alice@example.com',
role: 'admin'
});
await user.save(); // validates then saves to 'users' collection
// Method 2: User.create() shorthand
const user2 = await User.create({
name: 'Bob',
email: 'bob@example.com'
});
console.log('Created user ID:', user2._id);
// Method 3: insertMany for bulk
await User.insertMany([
{ name: 'Carol', email: 'carol@example.com' },
{ name: 'Dave', email: 'dave@example.com' }
]);Propriedades Virtuais
Os virtuais são propriedades calculadas que não são armazenadas no banco de dados, mas calculadas a partir de outros campos do documento. Eles se comportam como campos comuns do documento no código da aplicação, mas nunca são gravados no MongoDB. Casos de uso comuns incluem combinar firstName e lastName em um virtual fullName, calcular a age a partir de um campo birthDate ou criar uma url pública a partir de um _id.
const personSchema = new mongoose.Schema({
firstName: String,
lastName: String,
birthDate: Date
});
// Virtual: combines firstName and lastName
personSchema.virtual('fullName').get(function () {
return this.firstName + ' ' + this.lastName;
// Use regular function (not arrow function) to access 'this'
});
// Virtual with a setter for convenience
personSchema.virtual('fullName').get(function () {
return this.firstName + ' ' + this.lastName;
}).set(function (v) {
this.firstName = v.split(' ')[0];
this.lastName = v.split(' ')[1];
});
const Person = mongoose.model('Person', personSchema);
const p = new Person({ firstName: 'Alice', lastName: 'Smith' });
console.log(p.fullName); // 'Alice Smith'Incluindo Virtuais na Saída JSON
Por padrão, os virtuais não são incluídos ao converter um documento para JSON (por exemplo, ao enviá-lo em uma resposta de API). Para incluí-los, defina { toJSON: { virtuals: true } } nas opções do esquema ou chame explicitamente doc.toJSON({ virtuals: true }). Em aplicações Express, res.json(doc) chama toJSON() automaticamente; portanto, definir toJSON: { virtuals: true } no esquema é a maneira mais simples de sempre incluí-los.
const userSchema = new mongoose.Schema(
{
firstName: String,
lastName: String
},
{
toJSON: { virtuals: true }, // include virtuals in res.json()
toObject: { virtuals: true } // include virtuals in .toObject()
}
);
userSchema.virtual('fullName').get(function () {
return this.firstName + ' ' + this.lastName;
});
const user = new User({ firstName: 'Alice', lastName: 'Smith' });
console.log(JSON.stringify(user)); // includes 'fullName': 'Alice Smith'Validação Personalizada em Esquemas
Os esquemas do Mongoose permitem definir funções validadoras personalizadas para cada campo. A função validadora recebe o valor do campo e deve retornar true quando ele for válido ou false (ou lançar um erro) quando for inválido. Também é possível fornecer uma mensagem de erro personalizada. Os validadores personalizados são executados antes de .save() e podem ser assíncronos, o que é útil para verificações de exclusividade no nível do banco de dados que vão além do índice exclusivo.
const productSchema = new mongoose.Schema({
name: String,
price: {
type: Number,
required: true,
validate: {
validator: function (v) {
return v > 0; // price must be positive
},
message: props => 'Price must be positive, got ' + props.value
}
},
sku: {
type: String,
validate: {
validator: function (v) {
return /^[A-Z]{2}-\d{4}$/.test(v); // format: AB-1234
},
message: 'SKU must match format AB-1234'
}
}
});Métodos e Estáticos do Esquema
Os esquemas aceitam métodos de instância (disponíveis em cada documento) e métodos estáticos (chamados na classe Model). Os métodos de instância acessam this para o documento específico, o que os torna ideais para operações específicas do documento, como comparar senhas ou formatar a saída. Os métodos estáticos são úteis para consultas comuns ou funções de fábrica que não operam em uma instância específica.
const userSchema = new mongoose.Schema({ email: String, passwordHash: String });
// Instance method: available on each user document
userSchema.methods.checkPassword = function (candidatePassword) {
return bcrypt.compare(candidatePassword, this.passwordHash);
};
// Static method: called on the User model
userSchema.statics.findByEmail = function (email) {
return this.findOne({ email: email.toLowerCase() });
};
const User = mongoose.model('User', userSchema);
// Usage:
const user = await User.findByEmail('alice@example.com'); // static
const valid = await user.checkPassword('secret'); // instance methodSubdocumentos versus Objetos de Esquema Aninhados
O Mongoose diferencia subdocumentos incorporados (definidos como um array de esquemas) de objetos de esquema aninhados (uma definição de esquema simples dentro de um campo). Cada subdocumento de um array recebe seu próprio _id e pode ser manipulado como um documento individual por meio de doc.items.id(subId). Os objetos aninhados compartilham o ciclo de vida do documento pai. Use subdocumentos em arrays para coleções ordenadas de registros (itens de linha de pedidos, comentários). Use objetos aninhados para estruturas incorporadas de um para um (endereço, metadados).
// Nested object — no array, no _id per entry
const userSchema = new Schema({
address: {
street: String,
city: String,
zip: String
}
});
// Array subdocuments — each item gets its own _id
const orderSchema = new Schema({
items: [
{
productId: Schema.Types.ObjectId,
quantity: Number,
price: Number
// _id auto-added to each item
}
]
});
// Access subdocument by ID:
const item = order.items.id(someItemId);Verificação Rápida
Verifique sua compreensão dos conceitos de MongoDB e bancos de dados NoSQL apresentados nesta lição.
Recapitulação da Lição
Nesta lição, você aprendeu que: os esquemas do Mongoose definem a estrutura, os tipos e as regras de validação dos documentos; os modelos são compilados a partir de esquemas e fornecem a interface de consulta e escrita (Model.find(), new Model() etc.); e os virtuais são propriedades calculadas que existem na memória, mas nunca são armazenadas no MongoDB — úteis para campos derivados como fullName ou url. A seguir, exploraremos a API de consultas do Mongoose, incluindo o encadeamento, .lean() e a comparação com o controlador nativo.
Aprenda JavaScript com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 30
- Aulas
- 120
Perguntas Frequentes
A aula “Esquemas, modelos e virtuais do Mongoose” é grátis?
Sim — o texto completo de “Esquemas, modelos e virtuais do Mongoose” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de MongoDB Academy, atualize para CoddyKit PRO. O curso de MongoDB Academy inclui 4 aulas no total.
O que vou aprender em “Esquemas, modelos e virtuais do Mongoose”?
Você definirá esquemas do Mongoose com tipo, validação e opções padrão, criará modelos e adicionará propriedades virtuais. Você pratica MongoDB Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar MongoDB Academy?
Nenhuma experiência prévia é necessária. MongoDB Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Esquemas, modelos e virtuais do Mongoose”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de MongoDB Academy?
Sim. Cada aula de MongoDB Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Conectando-se com o driver oficial do Node.js
- Esquemas, modelos e virtuais do Mongoose
- Consultas do Mongoose, encadeamento e documentos enxutos
- Middleware do Mongoose: ganchos anteriores e posteriores