Mongoose中的鉴别器

1,281 阅读2分钟

鉴别器(discriminator)是一种模型继承机制,可以在同一个集合(collecton)中定义不同的结构。举个例子,假如我们的业务中有两个实体 customer 和 order,正常情况下肯定是创建两个模型:

  1. 客户模型

    const Customer = mongoose.model('Customer', new mongoose.Schema({
        firstName: { type: String },
        lastName: { type: String },
        email: { type: String }
    }))
    
  2. 订单模型

    const Order = mongoose.model('Order', new mongoose.Schema({
        orderDate: { type: Date, default: Date.now },
        items: [String]
    }))
    

然后写数据的时候分别用:

  1. 创建客户

    const customer = new Customer({ firstName: "John", lastName: "Doe", email: "john@doe.com" })
    customer.save((err, savedCustomer) => console.log(JSON.stringify(savedCustomer)))
    
  2. 创建订单

    const order = new Order({ items: ["apple", "orange", "pear"] })
    order.save((err, savedOrder) => console.log(JSON.stringify(savedOrder)))
    

这样客户集合和订单集合里面分别各有一条数据了。

但是如果利用 discriminator,我们却可以把这两个完全无关的模型放到同一个表中,举个例子,我们先创建一个 Base 模型,集合的名称叫 data,然后指定 discriminatorKey 为 __type(如果不指定的话,默认为 __t):

const baseOptions = { discriminatorKey: '__type', collection: 'data' }
const Base = mongoose.model('Base', new mongoose.Schema({}, baseOptions))

接下来可以让 Customer 和 Order 都继承自这个 Base 模型:

const Customer = Base.discriminator('Customer', new mongoose.Schema({
    firstName: { type: String },
    lastName: { type: String },
    email: { type: String }
}))
const Order = Base.discriminator('Order', new mongoose.Schema({
    orderDate: { type: Date, default: Date.now },
    items: [String]
}))

代码改动很少,我们依然可以用 Customer 和 Order 模型来创建或查询数据,不过最终都放到了 data 集合里面,该集合的每条数据中都有一个 __type 字段用于区分类型,在上面的例子当中就是 Customer 和 Order。

那这样做有啥好处呢?就上面的例子来讲,放在一起并不合适,除非你买的云数据库是按照集合数量进行计费的,否则还是老老实实地放在两张表里面把,符合语义也方便查询。但是有些场景下,字段相似的集合就可以合并了,特别是有些表的字段是动态的,你可能选择用 Mixed 类型(这就好比 TypeScript 中的 any 一样虽然强大但无法推断具体类型),但 discriminator 或许是更好的选择。