Мангуст: Как смоделировать внешний ключ / обратное отношение? - PullRequest
5 голосов
/ 30 октября 2011

Я использую Mongoose для моделирования коллекций Person и Transaction, где каждая 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 была коллекция всех Transaction s, для которых они имеют значение to или from. Пока что это лучший способ, которым я смог понять, как это сделать:

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 слишком похоже на реляционную базу данных? Вместо того чтобы иметь коллекцию Transaction, связанную с каждым экземпляром Person, я должен просто запросить коллекцию Translation напрямую?

Спасибо.

1 Ответ

7 голосов
/ 04 ноября 2011

Вам нужно больше думать о запросах, которые вы собираетесь выполнять в базе данных, когда разрабатываете схему MongoDB.Попробуйте продублировать данные для скорости и ссылаться на них для целостности.Что это значит?Ну, например, когда вы делаете запрос для транзакции, я думаю, вам не нужны все данные пользователя с первого раза, нет?(Вам нужна электронная почта пользователя, местоположение при отображении информации о транзакции?)Я думаю, что вам, вероятно, просто нужен идентификатор пользователя и имя пользователя, поэтому вы должны сделать что-то вроде этого:

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 запроса для страницы, отображающей детали транзакции (один для транзакции и 2 дополнительных запроса для имен пользователей), у вас будет только один.Это всего лишь пример, вы можете применить ту же логику для схемы пользователя, в зависимости от того, чего вы пытаетесь достичь.

В любом случае, я не думаю, что ваше промежуточное ПО в порядке, поскольку вы не проверяетеошибки там (вы всегда звоните дальше, несмотря ни на что).Вот как я бы написал промежуточное программное обеспечение (не тестировал, но идея важна):

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").

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...