我刚刚学习mongodb,正在寻求文档设计建议。在同一文档中,我希望嵌入式引用引用其他嵌入式引用。
想象一下,我有一个收藏品“个人资料”,它以一系列的东西开始。在某些时候,某些计算逻辑会查看thingILike以得出(并保存)结论。结论应该参考原始清单中的项目......
var myProfile = {
"thingsILike": [
{"type": "movie", "name": "300"},
{"type": "movie", "name": "gladiator"},
{"type": "tvshow", "name": "spartacus"}
],
"conclusions": [
{"ancientGore": [SOMEHOW REFERENCE: 300, gladiator, spartacus]},
{"gladiators": [SOMEHOW REFERENCE: gladiator, spartacus]}
]
}
假设我有2个列表的单个集合的正当理由,在结论条目中引用原始thingILike的最佳方法是什么?
我想得出结论保留thingIL的ObjectID列表(即使它们不是集合,也需要objectIds for thingsILike)。如果mongo(或mongoose)填充这些引用就像它们用于集合引用那样会很好。
那么,是否有一些已知的优雅模式或支持我尚未找到?或者我只需要在这里使用暴力并通过代码处理引用?
答案 0 :(得分:0)
我认为重新评估是否使用子文档数组是一个很好的设计选择。来自MongoLab post on subdocument arrays:“但是,必须小心。需要非常大的数组的数据模型,或者具有高修改率的数组,通常可以导致性能问题。“这可能不是您设计的问题,但值得重新审视。
继续讨论手头的问题,MongoDB没有为文档属性提供内部引用其他属性的方法。猫鼬可以virtuals的形式,但我不相信这会直接解决你的问题。
关于填充conclusions
中的值,假设“后一次计算”可能会为每个结论提供一个ObjectId数组,您需要对返回的文档进行后处理以填充值。这可以通过虚拟或通过猫鼬模型上的方法来完成。
使用虚拟getter的方法可以部分解决这个问题,但需要带有结论键的thingsILike
标记项。这种更新可以通过虚拟设置器完成,也可以直接通过“后期计算”完成。
使用这种方法,mongodb中的实际对象看起来像:
{
"thingsILike": [
{"type": "movie", "name": "300", conclusions: ["ancientGore"]},
{"type": "movie", "name": "gladiator", conclusions: ["ancientGore", "gladiators"]},
{"type": "tvshow", "name": "spartacus", conclusions: ["ancientGore", "gladiators"]}
]
}
conclusions
的虚拟路径为:
MyProfileSchema.virtual('conclusions').get(function () {
// `this` is the parent document
// Iterate over things and create conclusions
return this.thingsILike.reduce(function createConclusions(conclusions, thing) {
if (Array.isArray(thing.conclusions)) {
thing.conclusions.forEach(function assignConclusion(conclusion) {
if (conclusions[conclusion] === undefined) {
conclusions[conclusion] = [];
}
conclusions[conclusion].push(thing);
});
}
return conclusions;
}, {});
});
请注意,这是一个如何使用虚拟getter的示例,并且可以对其进行各种优化。例如,如果thingsILike
被更新,则缓存对象并仅重建对象。