【问题标题】:Mongoose relations design猫鼬关系设计
【发布时间】:2017-03-31 16:49:04
【问题描述】:

我最近开始在 Node.js 应用程序中将 Mongoose 与 Express.js 一起使用,我有一个关于设计架构的正确方法的问题。

我有几个模式有一些关系,即 Location 模式有一个对象数组(在这个上下文中它不是 JS 对象),并且 Object 模式有它的 Location 属性。我了解到 Mongoose 中的关系是使用人口来解决的,但是当我实现这种方法时,我注意到我必须输入很多重复的代码,即每当我想创建一个新对象时,我还必须更新 Location 的数组对象,然后将位置分配给对象的属性。仅手动组装所有具有 locationId 属性的对象,该属性等于我想在单独的查询中从数据库中获取的位置,这不是更简单吗?

我也考虑过将对象存储在位置文档中的数组中(作为子文档),但我决定我希望能够与位置分开使用对象(创建、删除、更新)(不查询位置)所以我猜这种方法不符合我的需求。但是在我的情况下,人口也有其缺点,所以我想最好是手动收集特定位置的对象,通过该位置的 id 在单独的查询中。

我想听听该技术的一些专业或高级用户对设计 Mongoose 模式的意见,这样我和其他人就不会在以后维护和扩展我们的应用程序时遇到麻烦。

以下是我目前有问题的架构:

var locationSchema = new mongoose.Schema({
    title: String,
    objects: [{ type: String, ref: 'object' }]
});

var objectSchema = new mongoose.Schema({
    title: String,
    location: { type: String, ref: 'location' }
});

【问题讨论】:

  • 你能质疑你拥有的所有模式吗?
  • 我刚刚做到了。 :)
  • 对于那些感兴趣的人,我刚刚尝试将mongoose-autopopulate 与我的两个模式一起使用,结果出现内存不足错误。我相信这是由于循环引用而发生的:我请求了一个具有一个对象的位置,因此该位置自动填充了该对象,然后该对象自动请求其位置,然后该位置再次请求其对象,此循环一直持续到OOM 错误。所以那些在你的模式中有一些循环引用的人(我相信这种情况经常发生)——不要尝试使用mongoose-autopopulate
  • 因为您正在架构中进行交叉关系,并且自动填充遍历循环引用并且内存不足(:
  • 是的,我自己已经解释过了。 :)

标签: node.js mongodb relationships mongoose-schema mongoose-populate


【解决方案1】:

查看此示例

db/schemas.js:

const Schema = mongoose.Schema;

const ObjectSchema = {
    title: Schema.Types.String
}

const LocationSchema = new Schema({
    title: Schema.Types.String,
    objects: [{type: Schema.Types.ObjectId, ref: 'Object'}]
})

module.exports = {
  Object: ObjectSchema,
  Location: LocationSchema
};




db/model.js:

const 
 mongoose = require('mongoose'),
 schemas = require('./schemas');

module.exports = model => mongoose.model(model, schemas[model+'Schema']);




用法:

const 
  model = require('./db/model'),
  LocationModel = model('Location');

LocationModel
  .findOne({_id: 'some id here'})
  .populate('objects')
  .exec((err, LocationInstance) => {
    console.log(LocationInstance.title, ' objects:', LocationInstance.objects); 
  });




当您创建一个对象并希望与位置相关时:

const 
  model = require('./db/model'),
  ObjectModel = model('Object'),
  LocationModel = model('Location');

let 
  ObjectInstance = new ObjectModel({title: 'Something'});
  ObjectInstance.save((err, result) => {
    LocationModel
      .findByIdAndUpdate(
        'some id here', 
        {$push: {objects: ObjectInstance._id}},
        (err) => {
          console.log('Object:', ObjectInstance.title, ' added to location');
        });
  });




更新对象数据:

  const 
    model = require('./db/model'),
    ObjectModel = model('Object');

  let id = 'id of object';

  ObjectModel
    .findByIdAndUpdate(
      id, 
      {title: 'Something #2'},
      (err) => {
        console.log('Object title updated');
      });




按对象查找位置:

  const 
    model = require('./db/model'),
    LocationModel = model('Object');

  let id = 'id of object';

  LocationModel
    .findOne({objects: id})
    .populate('objects')
    .exec((err, LocationInstance) => {
      console.log('Location objects:', LocationInstance.objects);
    });

没有什么特别的findOne({objects: id}) 将在位置文档中搜索与对象数组中的 id 有关系


欢迎任何其他问题(:

【讨论】:

  • @Salivan 没有优缺点,只需使用您喜欢的方式,这对您来说很舒服,并确保您的代码易于阅读。 NodeJS 是一种用途广泛的技术。很难找到 2 个以相同方式完成任务的开发人员。
  • @Salivan 如果您使用 expressjs 寻找最佳实践,我建议您看看这个:terlici.com/2014/08/25/best-practices-express-structure.html
  • 嗯,我一直想以一种可以接受并经过测试的方式来完成事情。如果真的没有比人口更好的东西,我想我会继续使用它们,或者如果我发现它确实是一个开销,我将切换到单独的查询以通过 id 获取相关对象。
  • @Salivan,无需标记为已接受。没关系。也许有人会用好主意来回应。实际上,在 nodejs 的世界中,最好不要太复杂。如果您想查看我如何构建应用程序的示例:bitbucket.org/num8er/citymag-az-website 最佳实践文档的一点点开发版本。
  • 感谢您的资源!
猜你喜欢
  • 2014-06-15
  • 2023-03-19
  • 2014-12-09
  • 2015-05-20
  • 2018-01-22
  • 2018-08-23
  • 2014-10-17
  • 2016-11-15
  • 1970-01-01
相关资源
最近更新 更多