阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > Schema的定义与结构

Schema的定义与结构

作者:陈川 阅读数:45354人阅读 分类: MongoDB

Schema的定义

Schema是Mongoose中用于定义数据模型结构的对象,它描述了文档的字段类型、默认值、验证规则等信息。Schema不直接操作数据库,而是作为Model的模板,通过Model进行CRUD操作时会根据Schema的定义进行类型转换和验证。

const mongoose = require('mongoose');
const { Schema } = mongoose;

// 定义一个用户Schema
const userSchema = new Schema({
  username: String,
  age: Number,
  isAdmin: Boolean
});

Schema的基本结构

Schema由字段定义组成,每个字段需要指定类型。Mongoose支持以下基本类型:

  • String
  • Number
  • Boolean
  • Date
  • Buffer
  • ObjectId
  • Array
  • Mixed
const productSchema = new Schema({
  name: String,  // 字符串类型
  price: Number, // 数字类型
  inStock: Boolean, // 布尔类型
  createdAt: Date, // 日期类型
  tags: [String], // 字符串数组
  meta: Schema.Types.Mixed // 混合类型
});

字段配置选项

每个字段可以配置多种选项来控制其行为:

const bookSchema = new Schema({
  title: {
    type: String,
    required: true, // 必填字段
    trim: true, // 自动去除前后空格
    minlength: 3, // 最小长度
    maxlength: 100 // 最大长度
  },
  published: {
    type: Date,
    default: Date.now // 默认值
  },
  edition: {
    type: Number,
    min: 1, // 最小值
    max: 10 // 最大值
  }
});

嵌套Schema

Schema可以嵌套其他Schema来构建复杂的数据结构:

const addressSchema = new Schema({
  street: String,
  city: String,
  zipCode: String
});

const customerSchema = new Schema({
  name: String,
  addresses: [addressSchema], // 嵌套Schema数组
  primaryAddress: addressSchema // 单个嵌套Schema
});

自定义验证器

Schema支持自定义验证逻辑:

const orderSchema = new Schema({
  items: [{
    productId: Schema.Types.ObjectId,
    quantity: {
      type: Number,
      validate: {
        validator: function(v) {
          return v > 0; // 自定义验证函数
        },
        message: props => `${props.value}不是有效的数量`
      }
    }
  }]
});

虚拟属性

虚拟属性是不存储在数据库中的计算属性:

const personSchema = new Schema({
  firstName: String,
  lastName: String
});

// 定义虚拟属性fullName
personSchema.virtual('fullName').get(function() {
  return `${this.firstName} ${this.lastName}`;
});

中间件

Schema支持pre和post中间件,可以在特定操作前后执行代码:

const blogSchema = new Schema({
  title: String,
  content: String,
  views: Number
});

// 保存前中间件
blogSchema.pre('save', function(next) {
  if (!this.views) {
    this.views = 0;
  }
  next();
});

// 查询后中间件
blogSchema.post('find', function(docs) {
  console.log(`查询到${docs.length}篇博客`);
});

索引定义

可以在Schema中定义索引以提高查询性能:

const productSchema = new Schema({
  name: { type: String, index: true }, // 单字段索引
  category: String,
  price: Number
});

// 复合索引
productSchema.index({ category: 1, price: -1 });

自定义方法

可以为Schema添加自定义实例方法和静态方法:

const animalSchema = new Schema({
  name: String,
  type: String
});

// 实例方法
animalSchema.methods.findSimilarTypes = function(cb) {
  return this.model('Animal').find({ type: this.type }, cb);
};

// 静态方法
animalSchema.statics.findByName = function(name) {
  return this.find({ name: new RegExp(name, 'i') });
};

插件系统

Schema支持插件扩展功能:

// 定义一个简单的插件
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();
  });
}

// 应用插件
const postSchema = new Schema({ title: String });
postSchema.plugin(timestampPlugin);

查询帮助方法

可以扩展查询接口:

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

// 使用扩展的查询方法
User.find().byName('john').exec();

多态关联

通过Schema实现多态关联:

const commentSchema = new Schema({
  content: String,
  commentable: {
    kind: String, // 关联模型类型
    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 }));

// 创建关联评论
const comment = new Comment({
  content: 'Great post!',
  commentable: {
    kind: 'Post',
    item: post._id
  }
});

动态引用

Schema支持动态引用字段:

const orderSchema = new Schema({
  customer: {
    type: Schema.Types.ObjectId,
    ref: 'User' // 静态引用
  },
  product: {
    type: Schema.Types.ObjectId,
    ref: function() {
      return this.productType; // 动态引用
    }
  },
  productType: String
});

模式选项

创建Schema时可以指定多种选项:

const options = {
  timestamps: true, // 自动添加createdAt和updatedAt
  toJSON: { virtuals: true }, // 转换JSON时包含虚拟属性
  toObject: { virtuals: true },
  id: false, // 禁用默认的id虚拟属性
  _id: false, // 禁用_id字段
  versionKey: '__v' // 自定义版本键
};

const logSchema = new Schema({
  message: String
}, options);

模式继承

可以通过继承创建相关Schema:

// 基础Schema
const options = { discriminatorKey: 'kind' };
const eventSchema = new Schema({ time: Date }, options);

// 继承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);

模式别名

可以为字段定义别名:

const personSchema = new Schema({
  n: { type: String, alias: 'name' }, // 数据库中用n,代码中用name
  a: { type: Number, alias: 'age' }
});

const person = new Person({ name: 'John', age: 30 });
console.log(person.name); // 'John'
console.log(person.n); // undefined (除非显式设置)

模式类型扩展

可以扩展自定义Schema类型:

// 自定义email类型
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, '不是有效的邮箱地址');
  }
});

// 使用自定义类型
const contactSchema = new Schema({
  email: mongoose.Schema.Types.Email
});

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌