mongoose4.5中文教程
  • Introduction
  • Mongoose
  • guide
    • 模式(schemas)
      • 模式类型(types)
      • 自定义类型(custom)
    • 模型(models)
    • 文档(documents)
      • 子文档(sub docs)
      • 默认值(defaults)
    • 查询(queries)
    • 验证(validation)
    • 中间件(middleware)
    • 联表(population)
    • 连接(connections)
    • 插件(plugins)
    • 承诺(promises)
    • 鉴频器(discriminators)
    • 贡献
    • ES2015 整合
    • 浏览器中的schemas
    • 自定义schema类型
    • MongoDB版本兼容性
    • 3.6 发布说明
    • 3.8 发布说明
    • 4.0 发布说明
  • API 文档
Powered by GitBook
On this page
  • The model.discriminator() function
  • 鉴别器保存事件模型的集合
  • 鉴别器的键
  • 鉴别器添加鉴别键查询
  • 鉴别器复制的前置和后置钩子
  • 处理自定义_id字段

Was this helpful?

  1. guide

鉴频器(discriminators)

Previous承诺(promises)Next贡献

Last updated 6 years ago

Was this helpful?

原文: 翻译:小虾米(QQ:509129)

The model.discriminator() function

鉴别器是一个模式继承机制。他们使你重叠模式上同一标的MongoDB集合有多个模型。

假设你想在一个集合中跟踪不同类型的事件。每一件事件都会有一个时间戳,但事件表示点击链接应该有一个URL。你可以使用model.discriminator()函数。这个函数需要2个参数,一个模型的名字和一个鉴频器模式。它返回一个模型是基础模式的结合和鉴频器模式。

 var options = {discriminatorKey: 'kind'};

    var eventSchema = new mongoose.Schema({time: Date}, options);
    var Event = mongoose.model('Event', eventSchema);

    // ClickedLinkEvent is a special type of Event that has
    // a URL.
    var ClickedLinkEvent = Event.discriminator('ClickedLink',
      new mongoose.Schema({url: String}, options));

    // When you create a generic event, it can't have a URL field...
    var genericEvent = new Event({time: Date.now(), url: 'google.com'});
    assert.ok(!genericEvent.url);

    // But a ClickedLinkEvent can
    var clickedEvent =
      new ClickedLinkEvent({time: Date.now(), url: 'google.com'});
    assert.ok(clickedEvent.url);

鉴别器保存事件模型的集合

假设你创建一个鉴别器跟踪事件,新用户注册。这些SignedUpEvent实例将被存储在相同的集合作为通用的事件和ClickedLinkEvent实例。

var event1 = new Event({time: Date.now()});
    var event2 = new ClickedLinkEvent({time: Date.now(), url: 'google.com'});
    var event3 = new SignedUpEvent({time: Date.now(), user: 'testuser'});

    var save = function (doc, callback) {
      doc.save(function (error, doc) {
        callback(error, doc);
      });
    };

    async.map([event1, event2, event3], save, function (error) {

      Event.count({}, function (error, count) {
        assert.equal(count, 3);
      });
    });

鉴别器的键

mongoose讲述不同的鉴别模型之间的差异是由“鉴频器的键”,默认是__t。Mongoose添加一个叫做__t字符串路径到你的模式中,它采用追踪鉴别本文档实例。

var event1 = new Event({time: Date.now()});
    var event2 = new ClickedLinkEvent({time: Date.now(), url: 'google.com'});
    var event3 = new SignedUpEvent({time: Date.now(), user: 'testuser'});

    assert.ok(!event1.__t);
    assert.equal(event2.__t, 'ClickedLink');
    assert.equal(event3.__t, 'SignedUp');

鉴别器添加鉴别键查询

鉴别器模型是特殊的;他们重视鉴别键查询。换句话说,find(), count(), aggregate(),等等,有足够的智慧来解释鉴别器。

 var event1 = new Event({time: Date.now()});
    var event2 = new ClickedLinkEvent({time: Date.now(), url: 'google.com'});
    var event3 = new SignedUpEvent({time: Date.now(), user: 'testuser'});

    var save = function (doc, callback) {
      doc.save(function (error, doc) {
        callback(error, doc);
      });
    };

    async.map([event1, event2, event3], save, function (error) {

      ClickedLinkEvent.find({}, function (error, docs) {
        assert.equal(docs.length, 1);
        assert.equal(docs[0]._id.toString(), event2._id.toString());
        assert.equal(docs[0].url, 'google.com');
      });
    });

鉴别器复制的前置和后置钩子

作者也使用他们的基础模式的前置和后置的中间件。然而,你也可以把中间件来鉴别模式不影响基础模式。

 var options = {discriminatorKey: 'kind'};

    var eventSchema = new mongoose.Schema({time: Date}, options);
    var eventSchemaCalls = 0;
    eventSchema.pre('validate', function (next) {
      ++eventSchemaCalls;
      next();
    });
    var Event = mongoose.model('GenericEvent', eventSchema);

    var clickedLinkSchema = new mongoose.Schema({url: String}, options);
    var clickedSchemaCalls = 0;
    clickedLinkSchema.pre('validate', function (next) {
      ++clickedSchemaCalls;
      next();
    });
    var ClickedLinkEvent = Event.discriminator('ClickedLinkEvent',
      clickedLinkSchema);

    var event1 = new ClickedLinkEvent();
    event1.validate(function () {
      assert.equal(eventSchemaCalls, 1);
      assert.equal(clickedSchemaCalls, 1);

      var generic = new Event();
      generic.validate(function () {
        assert.equal(eventSchemaCalls, 2);
        assert.equal(clickedSchemaCalls, 1);
      });
    });

处理自定义_id字段

鉴别器的字段是基础模式的字段和鉴别器模式的字段的结合,并且鉴频器模式的字段优先。这种行为变得古怪当你有一个自定义_id字段。一个模式默认情况下得有_id字段,所以基础模式的_id字段将得到由鉴别器模式的默认_id字段覆盖。

你可以通过设置_id选项为false 在鉴别器的模式如下图所示。

var options = {discriminatorKey: 'kind'};

    // Base schema has a String _id...
    var eventSchema = new mongoose.Schema({_id: String, time: Date},
      options);
    var Event = mongoose.model('BaseEvent', eventSchema);

    var clickedLinkSchema = new mongoose.Schema({url: String}, options);
    var ClickedLinkEvent = Event.discriminator('ChildEventBad',
      clickedLinkSchema);

    var event1 = new ClickedLinkEvent();
    // Woops, clickedLinkSchema overwrote the custom _id
    assert.ok(event1._id instanceof mongoose.Types.ObjectId);

    // But if you set `_id` option to false...
    clickedLinkSchema = new mongoose.Schema({url: String},
      {discriminatorKey: 'kind', _id: false});
    ClickedLinkEvent = Event.discriminator('ChildEventGood',
      clickedLinkSchema);

    // The custom _id from the base schema comes through
    var event2 = new ClickedLinkEvent({_id: 'test'});
    assert.ok(event2._id.toString() === event2._id);
The model.discriminator() function