首页 文章

如何使用不同类型的引用和填充

提问于
浏览
-1

所以我有两个模式,文章和事件都有一个图像字段 .

对于文章,

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'
            }]
    };)

但是,它一直给我一个强制转换错误,因为当卡片属于Event类型时,它会很好地填充,但是当它是“Article”类型时,feature_image字段是字符串类型,因此无法填充 .

如果card类型为Event或者它是引用id而不是string,我如何填充featured_image字段 .

1 回答

  • 0

    而不是你试图做的事情,你应该使用“鉴别器”,这实际上是处理对象类型在给定参考中变化的关系的正确方法 .

    您可以通过定义模型的不同方式使用鉴别器,而不是使用“基本模型”和模式构建,如下所示:

    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);
    

    因此,您可以在此处定义"base model",例如 Content ,您实际上将引用指向 Event .

    下一部分是不同的模式实际上通过基本模型中的 .discriminator() 方法注册到此模型,而不是 .model() 方法 . 这将使模式与通用 Content 模型一起注册,当您引用使用 .discriminator() 定义的任何模型实例时,使用注册的模型名称在该数据中隐含存在特殊的 __t 字段 .

    除了在不同类型上启用mongoose到 .populate() 之外,这还具有附加到不同类型的项目的"full schema"的优点 . 因此,如果您愿意,您可以使用不同的验证和其他方法 . 确实"polymorphism"在数据库上下文中工作,附加了有用的模式对象 .

    因此,我们可以演示已完成的各种"joins",以及您现在可以使用 ArticleEvent 的单独模型,这些模型仅处理所有查询和操作中的那些项目 . 您不仅可以使用"individually",而且由于此机制实际上将数据存储在同一个集合中,因此还有一个 Content 模型可以访问这两种类型 . 这实质上是主关系如何在 Event 模式的定义中起作用 .

    As a full listing

    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();
      }
    );
    

    And the sample output for different queries

    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"
      }
    ]
    

相关问题