【问题标题】:MongoDB embedded docs referencing other embedded docsMongoDB 嵌入式文档引用其他嵌入式文档
【发布时间】:2015-06-25 02:25:20
【问题描述】:

我正在学习 mongodb,正在寻求文档设计建议。在同一个文档中,我希望嵌入引用引用其他嵌入引用。

假设我有一个集合“Profiles”,它以事物列表开头。稍后,一些计算逻辑会查看事物以得出(并保存)结论。结论应该参考原列表中的项目...

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 的最佳方法是什么?

我希望得出结论,保留 thingsILike 的 ObjectID 列表(即使它们不是集合,也需要 thingsILike 的 objectIds)。如果 mongo(或 mongoose)像集合引用一样填充这些引用,那就太好了。

那么,我还没有找到一些已知的优雅模式或对此的支持吗?还是我只需要在这里使用蛮力并通过代码处理引用?

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    我认为重新评估使用子文档数组是否是一个好的设计选择是值得的。来自 MongoLab post on subdocument arrays:“但是,必须小心。需要非常大的数组或修改率很高的数组的数据模型通常会导致性能问题。”这可能不是您的设计问题,但值得重新审视。

    转到手头的问题,MongoDB 不提供文档属性在内部引用其他属性的方法。猫鼬可以virtuals的形式,但我不相信这会直接解决你的问题。

    关于填充conclusions 中的值,假设“稍后计算”可能会为每个结论提供一个 ObjectId 数组,您需要对返回的文档进行后处理以填充这些值。这也可以通过 virtuals 或通过 mongoose 模型上的方法来完成。

    使用虚拟 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 更新时重建对象。

    【讨论】:

    • 感谢您的回复。我将更深入地研究虚拟方法。我确实考虑过长阵列性能问题。我的列表比我的示例所暗示的要小。我倾向于将参考列表保留在结论上,而不是保留在 ThingsILike 上,目的是不为计算结果而更改原始数据。再次感谢您帮助我穿越这个新世界;)。
    猜你喜欢
    • 1970-01-01
    • 2012-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 2012-01-11
    • 2015-02-06
    相关资源
    最近更新 更多