Discriminators鉴频器

The model.discriminator() functionmodel.discriminator()函数

Discriminators are a schema inheritance mechanism. 鉴别器是一种模式继承机制。They enable you to have multiple models with overlapping schemas on top of the same underlying MongoDB collection.它们使您能够在同一底层MongoDB集合上拥有多个具有重叠模式的模型。

Suppose you wanted to track different types of events in a single collection. 假设您想在一个集合中跟踪不同类型的事件。Every event will have a timestamp, but events that represent clicked links should have a URL. 每个事件都有一个时间戳,但表示单击链接的事件应该有一个URL。You can achieve this using the model.discriminator() function. 您可以使用model.discriminator()函数来实现这一点。This function takes 3 parameters, a model name, a discriminator schema and an optional key (defaults to the model name). 此函数采用3个参数,一个模型名称、一个鉴别器模式和一个可选键(默认为模型名称)。It returns a model whose schema is the union of the base schema and the discriminator schema.它返回一个模型,该模型的模式是基本模式和鉴别器模式的并集。

const options = { discriminatorKey: 'kind' };

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

// ClickedLinkEvent is a special type of Event that has a URL.ClickedLinkEvent是一种特殊类型的具有URL的事件。
const ClickedLinkEvent = Event.discriminator('ClickedLink',
new mongoose.Schema({ url: String }, options));

// When you create a generic event, it can't have a URL field...创建通用事件时,它不能有URL字段……
const genericEvent = new Event({ time: Date.now(), url: 'google.com' });
assert.ok(!genericEvent.url);

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

Discriminators save to the Event model's collection鉴别器保存到事件模型的集合

Suppose you created another discriminator to track events where a new user registered. 假设您创建了另一个鉴别器来跟踪新用户注册的事件。These SignedUpEvent instances will be stored in the same collection as generic events and ClickedLinkEvent instances.这些SignedUpEvent实例将与泛型事件和ClickedLinkEvent实例存储在同一集合中。

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


await Promise.all([event1.save(), event2.save(), event3.save()]);
const count = await Event.countDocuments();
assert.equal(count, 3);

Discriminator keys鉴别器键

The way Mongoose tells the difference between the different discriminator models is by the 'discriminator key', which is __t by default. Mongoose通过“discriminator key”(默认为__t)来判断不同鉴别器模型之间的差异。Mongoose adds a String path called __t to your schemas that it uses to track which discriminator this document is an instance of.Mongoose向您的模式添加了一个名为__t的String路径,用于跟踪此文档是哪个鉴别器的实例。

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

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

Updating the discriminator key更新鉴别器密钥

By default, Mongoose doesn't let you update the discriminator key. 默认情况下,Mongoose不允许您更新鉴别器密钥。save() will throw an error if you attempt to update the discriminator key. 如果您试图更新鉴别器键,save()将抛出一个错误。And findOneAndUpdate(), updateOne(), etc. will strip out discriminator key updates.findOneAndUpdate()updateOne()等将删除鉴别器密钥更新。

let event = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
await event.save();

event.__t = 'SignedUp';
// ValidationError: ClickedLink validation failed: __t: Cast to String failed for value "SignedUp" (type string) at path "__t"
await event.save();

event = await ClickedLinkEvent.findByIdAndUpdate(event._id, { __t: 'SignedUp' }, { new: true });
event.__t; // 'ClickedLink', update was a no-op

To update a document's discriminator key, use findOneAndUpdate() or updateOne() with the overwriteDiscriminatorKey option set as follows.要更新文档的鉴别器键,请使用findOneAndUpdate()updateOne(),并按如下方式设置overwriteDiscriminatorKey选项。

let event = new ClickedLinkEvent({ time: Date.now(), url: 'google.com' });
await event.save();

event = await ClickedLinkEvent.findByIdAndUpdate(
event._id,
{ __t: 'SignedUp' },
{ overwriteDiscriminatorKey: true, new: true }
);
event.__t; // 'SignedUp', updated discriminator key