【问题标题】:Mongoose: How to model a foreign key/inverse relationship?Mongoose:如何建模外键/反向关系?
【发布时间】:2011-12-18 08:05:51
【问题描述】:

我正在使用 Mongoose 为 PersonTransaction 集合建模,其中每个 Transaction 将引用两个不同的 Person 实例:

var TransactionSchema = new Schema({
  , amount          : { type: Number, required: true }
  , from            : { type: ObjectId, required: true }
  , to              : { type: ObjectId, required: true }
  , date            : Date
});

var PersonSchema = new Schema({
    name            : { type: String, required: true }
  , transactions    : [ObjectId]
});

我希望每个Person 都拥有一个集合所有Transactions,它们是tofrom 的值。到目前为止,这是我能够弄清楚如何做到这一点的最佳方法:

TransactionSchema.pre('save', function(next, done) {
    var transaction = this;

    Person.findById(this.to, function (err, person) {
        person.transactions.push(transaction);
        person.save();
    });

    Person.findById(this.from, function (err, person) {
        person.transactions.push(transaction);
        person.save();
    });

    next();
});

这似乎太过分了。有没有更好的方法来做到这一点,或者我是否试图像使用关系数据库一样使用 MongoDB?我应该直接查询Translation 集合,而不是与每个Person 实例关联的Transactions 集合吗?

谢谢。

【问题讨论】:

    标签: mongodb node.js mongoose


    【解决方案1】:

    在设计 MongoDB 架构时,您必须更多地考虑要在数据库上执行的查询。

    尝试复制数据以提高速度并引用它以确保完整性。这是什么意思?
    好吧,例如,当您查询交易时,我想您不需要第一次的所有用户详细信息,不是吗? (在交易中显示信息时是否需要用户的电子邮件、位置?)
    我认为您可能只需要用户 ID 和用户名,因此您应该执行以下操作:

    var TransactionSchema = new Schema({
      , amount          : { type: Number, required: true }
      , from            : { 
         user_id: {
           type: ObjectId
         , required: true
        }
       , username: {
           type: String
         , required: true
        } 
      }
      , to              : { 
         user_id: {
           type: ObjectId
         , required: true
        }
       , username: {
           type: String
         , required: true
        } 
      }
      , date            : Date
    });
    

    因此,您无需对显示交易详细信息的页面进行 3 次查询(1 次用于交易,2 次额外查询用于用户名),而只需一次。
    这只是一个示例,您可以对 User 架构应用相同的逻辑,具体取决于您要实现的目标。

    无论如何,我认为您的中间件不行,因为您没有在那里检查错误(无论如何,您总是调用 next )。这就是我编写中间件的方式(没有测试,但想法很重要):

    TransactionSchema.pre('save', function(next, done) {
      var transaction = this;
    
      Person.where('_id').in([this.to, this.from]).run(function (err, people) {
        if (people.length != 2) { next(new Error("To or from doesn't exist")); return; }
        Step(
          function save_to() {
            people[0].transactions.push(transaction);
            people[0].save(this);
          },
          function save_from(err) {
            if (err) { next(err); return; }
            people[1].transactions.push(transaction);
            people[1].save(this);
          },
          function callback(err) {
            next(err); 
          }
        );
      });
    });
    

    在上面的代码中,我使用Step 库进行流控制,并且我只使用一个查询而不是两个查询(在搜索“to”和“from”时)。

    【讨论】:

    • 在保存前还是保存后更好。如果由于验证错误或任何其他错误导致交易未保存怎么办。您不会亲自添加虚拟物品吗?如果您在保存后执行此操作,您将不得不再次查询交易
    猜你喜欢
    • 2014-11-18
    • 2015-09-23
    • 2020-12-10
    • 1970-01-01
    • 2020-02-12
    • 2021-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多