所以我有两个模式,文章和事件 两者都有一个图像区域。
对于文章,
featured_image: {
type: String,
default: '',
}
对于活动,
featured_image: {
type: Schema.ObjectId,
ref: 'Medium'
}
我有另一个架构,卡,像这样
type: {
type: String,
enum: ['Article', 'Event']
},
data: {
type: Schema.ObjectId,
refPath: 'type'
}
我正在尝试填充卡片,就像这样
Card
.find(query)
.populate({
path: 'data',
populate: [{
path: 'featured_image',
model: 'Medium',
select: 'source type'
}]
};)
然而,它一直给我一个强制转换错误,因为当card是Event类型时,它会填充正常,但是当它是'Article'类型时,featured_image字段是字符串类型,因此无法填充。
如果card类型为Event或者它是引用ID而不是字符串,我如何填充featured_image字段。
答案 0 :(得分:0)
您应该使用" discriminators"而不是您尝试做的事情,这实际上是处理对象类型在给定引用中变化的关系的正确方法。
您可以通过定义模型的不同方式使用鉴别器,而不是根据"基础模型构建#34;和架构如:
const contentSchema = new Schema({
name: String
});
const articleSchema = new Schema({
image: String,
});
const eventSchema = new Schema({
image: { type: Schema.Types.ObjectId, ref: 'Medium' }
});
const cardSchema = new Schema({
name: String,
data: { type: Schema.Types.ObjectId, ref: 'Content' }
});
const Medium = mongoose.model('Medium', mediumSchema);
const Card = mongoose.model('Card', cardSchema )
const Content = mongoose.model('Content', contentSchema);
const Article = Content.discriminator('Article', articleSchema);
const Event = Content.discriminator('Event', eventSchema);
所以你要定义一个"基础模型"例如Content
,您实际上将引用指向Event
。
下一部分是不同的模式实际上是通过基本模型中的.discriminator()
方法注册到此模型的,而不是.model()
方法。这会使模式与常规Content
模型一起注册,当您引用使用.discriminator()
定义的任何模型实例时,该数据中隐含存在特殊__t
字段,注册的型号名称。
除了在不同类型上启用mongoose到.populate()
之外,这还有一个优点:"完整架构"附在不同类型的物品上。因此,如果您愿意,您可以使用不同的验证和其他方法。确实是多态性"在数据库上下文中工作,附加有用的模式对象。
因此,我们可以展示各种各样的"加入&#34>完成后,您现在可以使用Article
和Event
的单个模型,这些模型仅处理所有查询和操作中的项目。并且您不仅可以单独使用"而且由于其机制实际上将数据存储在同一个集合中,因此还有一个Content
模型可以访问这两种类型。这实际上主要关系在Event
模式的定义中是如何工作的。
完整列表
const async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.set('debug',true);
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/cards');
const mediumSchema = new Schema({
title: String
});
const contentSchema = new Schema({
name: String
});
const articleSchema = new Schema({
image: String,
});
const eventSchema = new Schema({
image: { type: Schema.Types.ObjectId, ref: 'Medium' }
});
const cardSchema = new Schema({
name: String,
data: { type: Schema.Types.ObjectId, ref: 'Content' }
});
const Medium = mongoose.model('Medium', mediumSchema);
const Card = mongoose.model('Card', cardSchema )
const Content = mongoose.model('Content', contentSchema);
const Article = Content.discriminator('Article', articleSchema);
const Event = Content.discriminator('Event', eventSchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
async.series(
[
// Clean data
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),
// Insert some data
(callback) =>
async.waterfall(
[
(callback) =>
Medium.create({ title: 'An Image' },callback),
(medium,callback) =>
Content.create(
[
{ name: "An Event", image: medium, __t: 'Event' },
{ name: "An Article", image: "A String", __t: 'Article' }
],
callback
),
(content,callback) =>
Card.create(
[
{ name: 'Card 1', data: content[0] },
{ name: 'Card 2', data: content[1] }
],
callback
)
],
callback
),
// Query and populate
(callback) =>
Card.find()
.populate({
path: 'data',
populate: [{
path: 'image'
}]
})
.exec((err,cards) => {
if (err) callback(err);
log(cards);
callback();
}),
// Query on the model for the discriminator
(callback) =>
Article.findOne({},(err,article) => {
if (err) callback(err);
log(article);
callback();
}),
// Query on the general Content model
(callback) =>
Content.find({},(err,contents) => {
if (err) callback(err);
log(contents);
callback();
}),
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
);
以及不同查询的示例输出
Mongoose: cards.find({}, { fields: {} })
Mongoose: contents.find({ _id: { '$in': [ ObjectId("595ef117175f6850dcf657d7"), ObjectId("595ef117175f6850dcf657d6") ] } }, { fields: {} })
Mongoose: media.find({ _id: { '$in': [ ObjectId("595ef117175f6850dcf657d5") ] } }, { fields: {} })
[
{
"_id": "595ef117175f6850dcf657d9",
"name": "Card 2",
"data": {
"_id": "595ef117175f6850dcf657d7",
"name": "An Article",
"image": "A String",
"__v": 0,
"__t": "Article"
},
"__v": 0
},
{
"_id": "595ef117175f6850dcf657d8",
"name": "Card 1",
"data": {
"_id": "595ef117175f6850dcf657d6",
"name": "An Event",
"image": {
"_id": "595ef117175f6850dcf657d5",
"title": "An Image",
"__v": 0
},
"__v": 0,
"__t": "Event"
},
"__v": 0
}
]
Mongoose: contents.findOne({ __t: 'Article' }, { fields: {} })
{
"_id": "595ef117175f6850dcf657d7",
"name": "An Article",
"image": "A String",
"__v": 0,
"__t": "Article"
}
Mongoose: contents.find({}, { fields: {} })
[
{
"_id": "595ef117175f6850dcf657d6",
"name": "An Event",
"image": "595ef117175f6850dcf657d5",
"__v": 0,
"__t": "Event"
},
{
"_id": "595ef117175f6850dcf657d7",
"name": "An Article",
"image": "A String",
"__v": 0,
"__t": "Article"
}
]