使用Mongoose建模对嵌入文档的引用

时间:2014-09-10 11:14:14

标签: node.js mongodb mongoose

我在MongoDB中建模两种类型的事件(事件和子事件),如下所示:

var EventSchema = mongoose.Schema({
    'name' : String,
    'subEvent' : [ SubeventSchema ]
});

var SubeventSchema = mongoose.Schema({
    'name' : String
});

现在,当我查询子事件时,我希望能够检索有关其相应超级事件的数据,以便使用Mongoose填充功能检索的一些示例数据可能如下所示:

EventModel.findOne({
    name : 'Festival'
})
.populate('subEvent')
.execute(function (err, evt) { return evt; });

{
    name : 'Festival',
    subEvent: [
        { name : 'First Concert' },
        { name : 'Second Concert' }
    ]
}

EventModel.findOne({
    'subEvent.name' : 'FirstConcert'
}, {
    'subEvent.$' : 1
})
.populate('superEvent') // This will not work, this is the actual problem of my question
.execute(function (err, subevt) { return subevt; });

{
    name: 'First Concert',
    superEvent: {
        name: 'Festival'
    }
}

我能想到的解决方案不是嵌入,而是像这样引用:

var EventSchema = mongoose.Schema({
    'name' : String,
    'subEvent' : [ {
        'type' : mongoose.Schema.Types.ObjectId,
        'ref' : 'SubeventSchema'
    } ]
});

var SubeventSchema = mongoose.Schema({
    'name' : String,
    'superEvent' : {
        'type' : mongoose.Schema.Types.ObjectId,
        'ref' : 'EventSchema'
    }
});

我正在寻找基于使用嵌入式子事件的第一个示例的解决方案。这可以实现,如果是,如何?

2 个答案:

答案 0 :(得分:2)

我认为你的文档嵌入心理模型不正确。主要的误解(这是非常常见的)是你“查询子事件”(查询嵌入文档)。根据您当前的Event架构,Subevent只是嵌入在Event文档中的文档。嵌入式SubEvent不是顶级文档;它不是MongoDB中任何集合的成员。因此,您不会查询它。您查询Event具有某些属性的subEvents(模式中的实际集合级文档)。例如。人们翻译查询的一种方式

db.events.find({ "subEvent" : { "name" : "First Concert" } })

进入简单的英语是“找到所有名为”First Concert“的子事件。这是错误的。正确的翻译是”找到所有至少有一个子事件,其名称为“First Concert”的事件(“at”至少有一个“部分取决于subEvent是一个数组的知识。”

回到具体问题,你现在可以看到,试图在子事件中填充“超级预防”毫无意义。您的查询返回事件。最佳模式,无论是事件中嵌入的子事件,事件和子事件之间的单向或双向引用,单独集合中的文档,还是非规范化为组成子事件文档的事件,都无法根据问题中的信息确定,因为用例是未指定。

答案 1 :(得分:0)

也许这是一种需要修改思路而非模式本身的情况。 Mongoose .populate()支持MongoDB“投影”的基本思想,或者更常被称为“字段选择”。因此,不要试图围绕这个进行建模,只需选择要填充的字段。

因此,您的第二个架构表单完全有效,只需更改填充方式:

EventModel.find({}).populate("subEvent", "name").execute(function(err,docs) {

  // "subevent" array items only contain "name" now

});

这实际上已在"populate"部分的Mongoose文档中介绍。