使用虚拟属性访问Mongoose模型中的嵌套文档

时间:2016-02-03 21:25:36

标签: javascript node.js mongodb mongoose mongoose-populate

我试图在我的一个模式中创建一个虚拟项目,需要访问此模式中引用的项目所引用的数据(是,这2个引用深入,连接3个模式/模型)

我尝试使用Model / Schema A / B / C尽可能接近地模拟代码。

这将是 ModelA 的架构,其中包含取决于引用的虚拟项目:

// models/modela.js

// SchemaA for ModelA
const SchemaA = new Schema({
    _foo: {
        // References ModelB
        type: Schema.Types.ObjectId,
        ref: 'ModelB'
    }
})

// Virtual `Modela.something`, which needs the data from ModelC.baz
SchemaA.virtual('something').get(function () {
    // How can I access ModelC.baz
    return 'Value from ModelC'
});

然后是 ModelB 的架构:

// models/modelb.js

// SchemaB for ModelB
const SchemaB = new Schema({
    _bar: [{
        // References ModelC.baz
        type: Schema.Types.ObjectId,
        ref: 'ModelC'
    }]
})

ModelC 的架构:

// models/modelc.js

// SchemaC for ModelC
const SchemaC = new Schema({
    baz: Schema.Types.String
})

如您所见,我需要做的是从 ModelA

中的虚拟something项目中访问 Modelc.haz

我认为如果我通过查询本身做了两个人群,那么也许这会有用,所以我尝试了类似的东西:

this.find()
    .populate( '_foo' )
    .populate( '_foo._bar' )

哪个不起作用(我实际上并没有真正期待它,但是很好)

2 个答案:

答案 0 :(得分:1)

您可以使用Model.populate方法来实现此目的:

ModelA
  .find()
  .populate({
    path: '_foo'
  })
  .exec(function(err, docs) {
    if (err) throw err;

    // Populate the '_bar' array of the '_foo' property which is
    // an instance of ModelB
    ModelB.populate(docs[0]._foo, { path: '_bar' }, function(err, result) {
      console.log('Showing ModelC.baz:', docs[0].something);
    });
  });

您可以像这样定义虚拟属性:

SchemaA.virtual('something').get(function () {
    // How can I access ModelC.baz
    return this._foo._bar[0].baz;
});

答案 1 :(得分:0)

您可以在this github issue找到有关此内容的更多信息。您可以使用查询挂钩。

我有类似的问题,所以我用它来填充参考模型以用于虚拟功能。这是一个样本。

const tutorialSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    videos: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Video'
        }
    ]
});

tutorialSchema.pre('findOne', function (next) {
    this.populate('videos');  // now can be accessed using this.videos
    next();
});

tutorialSchema.virtual('totalTime').get(function () {
    let times = [];
    times = this.videos.map((v) => {
        return v.duration;
    });
    if(times.length === 0) return 0;
    let totalTime; // find total time of videos and then return
    return totalTime;
});