The definition and structure of a Schema
Definition of Schema
A Schema in Mongoose is an object used to define the structure of a data model. It describes the field types, default values, validation rules, and other information for documents. A Schema does not directly interact with the database but serves as a template for Models. When performing CRUD operations through a Model, type conversion and validation are carried out based on the Schema's definitions.
const mongoose = require('mongoose');
const { Schema } = mongoose;
// Define a user Schema
const userSchema = new Schema({
username: String,
age: Number,
isAdmin: Boolean
});
Basic Structure of Schema
A Schema consists of field definitions, where each field must specify a type. Mongoose supports the following basic types:
- String
- Number
- Boolean
- Date
- Buffer
- ObjectId
- Array
- Mixed
const productSchema = new Schema({
name: String, // String type
price: Number, // Number type
inStock: Boolean, // Boolean type
createdAt: Date, // Date type
tags: [String], // Array of strings
meta: Schema.Types.Mixed // Mixed type
});
Field Configuration Options
Each field can be configured with various options to control its behavior:
const bookSchema = new Schema({
title: {
type: String,
required: true, // Required field
trim: true, // Automatically trim whitespace
minlength: 3, // Minimum length
maxlength: 100 // Maximum length
},
published: {
type: Date,
default: Date.now // Default value
},
edition: {
type: Number,
min: 1, // Minimum value
max: 10 // Maximum value
}
});
Nested Schemas
Schemas can be nested within other Schemas to build complex data structures:
const addressSchema = new Schema({
street: String,
city: String,
zipCode: String
});
const customerSchema = new Schema({
name: String,
addresses: [addressSchema], // Array of nested Schemas
primaryAddress: addressSchema // Single nested Schema
});
Custom Validators
Schemas support custom validation logic:
const orderSchema = new Schema({
items: [{
productId: Schema.Types.ObjectId,
quantity: {
type: Number,
validate: {
validator: function(v) {
return v > 0; // Custom validation function
},
message: props => `${props.value} is not a valid quantity`
}
}
}]
});
Virtual Properties
Virtual properties are computed properties not stored in the database:
const personSchema = new Schema({
firstName: String,
lastName: String
});
// Define a virtual property fullName
personSchema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
Middleware
Schemas support pre
and post
middleware to execute code before or after specific operations:
const blogSchema = new Schema({
title: String,
content: String,
views: Number
});
// Pre-save middleware
blogSchema.pre('save', function(next) {
if (!this.views) {
this.views = 0;
}
next();
});
// Post-find middleware
blogSchema.post('find', function(docs) {
console.log(`Found ${docs.length} blog posts`);
});
Index Definitions
Indexes can be defined in Schemas to improve query performance:
const productSchema = new Schema({
name: { type: String, index: true }, // Single-field index
category: String,
price: Number
});
// Compound index
productSchema.index({ category: 1, price: -1 });
Custom Methods
Custom instance methods and static methods can be added to Schemas:
const animalSchema = new Schema({
name: String,
type: String
});
// Instance method
animalSchema.methods.findSimilarTypes = function(cb) {
return this.model('Animal').find({ type: this.type }, cb);
};
// Static method
animalSchema.statics.findByName = function(name) {
return this.find({ name: new RegExp(name, 'i') });
};
Plugin System
Schemas support plugins to extend functionality:
// Define a simple plugin
function timestampPlugin(schema) {
schema.add({
createdAt: Date,
updatedAt: Date
});
schema.pre('save', function(next) {
const now = Date.now();
this.updatedAt = now;
if (!this.createdAt) {
this.createdAt = now;
}
next();
});
}
// Apply the plugin
const postSchema = new Schema({ title: String });
postSchema.plugin(timestampPlugin);
Query Helper Methods
Query interfaces can be extended:
const queryPlugin = function(schema) {
schema.query.byName = function(name) {
return this.where({ name: new RegExp(name, 'i') });
};
};
const userSchema = new Schema({ name: String });
userSchema.plugin(queryPlugin);
// Use the extended query method
User.find().byName('john').exec();
Polymorphic Associations
Polymorphic associations can be implemented using Schemas:
const commentSchema = new Schema({
content: String,
commentable: {
kind: String, // Type of the associated model
item: { type: Schema.Types.ObjectId, refPath: 'commentable.kind' }
}
});
const Post = mongoose.model('Post', new Schema({ title: String }));
const Product = mongoose.model('Product', new Schema({ name: String }));
// Create an associated comment
const comment = new Comment({
content: 'Great post!',
commentable: {
kind: 'Post',
item: post._id
}
});
Dynamic References
Schemas support dynamically referenced fields:
const orderSchema = new Schema({
customer: {
type: Schema.Types.ObjectId,
ref: 'User' // Static reference
},
product: {
type: Schema.Types.ObjectId,
ref: function() {
return this.productType; // Dynamic reference
}
},
productType: String
});
Schema Options
Various options can be specified when creating a Schema:
const options = {
timestamps: true, // Automatically add createdAt and updatedAt
toJSON: { virtuals: true }, // Include virtuals when converting to JSON
toObject: { virtuals: true },
id: false, // Disable the default id virtual property
_id: false, // Disable the _id field
versionKey: '__v' // Custom version key
};
const logSchema = new Schema({
message: String
}, options);
Schema Inheritance
Related Schemas can be created through inheritance:
// Base Schema
const options = { discriminatorKey: 'kind' };
const eventSchema = new Schema({ time: Date }, options);
// Inherited Schema
const clickedEventSchema = new Schema({
element: String,
position: { x: Number, y: Number }
}, options);
const Event = mongoose.model('Event', eventSchema);
const ClickedEvent = Event.discriminator('Clicked', clickedEventSchema);
Schema Aliases
Aliases can be defined for fields:
const personSchema = new Schema({
n: { type: String, alias: 'name' }, // Use 'n' in the database, 'name' in code
a: { type: Number, alias: 'age' }
});
const person = new Person({ name: 'John', age: 30 });
console.log(person.name); // 'John'
console.log(person.n); // undefined (unless explicitly set)
Schema Type Extensions
Custom Schema types can be extended:
// Custom email type
function emailValidator(v) {
return /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/.test(v);
}
mongoose.Schema.Types.Email = mongoose.SchemaType.extend({
constructor: function Email(path, options) {
mongoose.SchemaTypes.String.call(this, path, options);
this.validate(emailValidator, 'Not a valid email address');
}
});
// Use the custom type
const contactSchema = new Schema({
email: mongoose.Schema.Types.Email
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn