ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 鉴频器(discriminators) > 原文:[The model.discriminator() function](http://mongoosejs.com/docs/discriminators.html) ## 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); ```