Как работать с асинхронным кодом в виртуальных свойствах Mongoose? - PullRequest
24 голосов
/ 21 мая 2011

Я пытаюсь работать с ассоциированными документами в разных коллекциях (не внедренными документами), и хотя в Mongooose существует проблема для этого , я пытаюсь обойти это сейчас, лениво загружаясвязанный документ с виртуальным свойством, как описано на веб-сайте Mongoose .

Проблема заключается в том, что метод получения для виртуального объекта принимает функцию в качестве аргумента и использует возвращаемое значение для виртуального свойства.Это замечательно, когда виртуальная машина не требует асинхронных вызовов для вычисления ее значения, но не работает, когда мне нужно сделать асинхронный вызов для загрузки другого документа.Вот пример кода, с которым я работаю:

TransactionSchema.virtual('notebook')
  .get( function() { // <-- the return value of this function is used as the property value
    Notebook.findById(this.notebookId, function(err, notebook) {
      return notebook; // I can't use this value, since the outer function returns before we get to this code
    })
    // undefined is returned here as the properties value
  });

Это не работает, поскольку функция возвращается до завершения асинхронного вызова.Есть ли способ, которым я мог бы использовать библиотеку управления потоком, чтобы сделать эту работу, или я мог бы изменить первую функцию, чтобы передать вызов findById получателю вместо анонимной функции?

Ответы [ 4 ]

21 голосов
/ 21 мая 2011

Вы можете определить виртуальный метод, для которого вы можете определить обратный вызов.

Используя ваш пример:

TransactionSchema.method('getNotebook', function(cb) {
  Notebook.findById(this.notebookId, function(err, notebook) {
    cb(notebook);
  })
});

И пока единственный комментатор представляется одним из этих педантичных типовВы также не должны бояться встраивания документов.Это одна из сильных сторон Mongos из того, что я понимаю.

Каждый использует приведенный выше код так:

instance.getNotebook(function(nootebook){
    // hey man, I have my notebook and stuff
});
5 голосов
/ 19 ноября 2012

Хотя это решает более широкую проблему, а не конкретный вопрос, я все же думал, что стоило представить:

Вы можете легко загрузить связанный документ из другой коллекции (результат которого почти идентичен определению виртуального) с помощью функции запроса Mongoose populate . Используя приведенный выше пример, для этого необходимо указать ref ObjectID в схеме Transaction (чтобы указать на коллекцию Notebook), а затем вызвать populate(NotebookId) при построении запроса. Связанная документация Mongoose решает эту проблему довольно тщательно.

Я не знаком с историей Мангуста, но, полагаю, populate не существовало, когда были представлены эти более ранние ответы.

3 голосов
/ 24 августа 2016

Поскольку это старый вопрос, я подумал, что он может использовать обновление.

Для достижения асинхронных виртуальных полей вы можете использовать mongoose-fill , как указано в выпуске github mongoose:https://github.com/Automattic/mongoose/issues/1894

3 голосов
/ 14 июня 2011

Подход Джоша отлично подходит для поиска отдельных документов, но моя ситуация была немного более сложной. Мне нужно было найти вложенное свойство для всего массива объектов. Например, моя модель выглядела так:

var TransactionSchema = new Schema({
  ...
  , notebooks: {type: [Notebook]}
});

var NotebookSchema = new Schema({
  ...
  , authorName: String  // this should not necessarily persist to db because it may get stale
  , authorId: String
});

var AuthorSchema = new Schema({
  firstName: String
  , lastName: String
});

Затем в коде моего приложения (я использую Express), когда я получаю транзакцию, я хочу, чтобы все записные книжки с фамилией автора:

...
TransactionSchema.findById(someTransactionId, function(err, trans) {
  ...
  if (trans) {
    var authorIds = trans.notebooks.map(function(tx) {
        return notebook.authorId;
      });

    Author.find({_id: {$in: authorIds}, [], function(err2, authors) {
      for (var a in authors) {
        for (var n in trans.notebooks {
          if (authors[a].id == trans.notebooks[n].authorId) {
            trans.notebooks[n].authorLastName = authors[a].lastName;
            break;
          }
        }
      }
      ...
    });

Это кажется крайне неэффективным и хакерским, но я не мог придумать другой способ сделать это. Наконец, я новичок в node.js, mongoose и stackoverflow, так что извините, если это не самое подходящее место для продолжения этого обсуждения. Просто решение Джоша было самым полезным в моем возможном «решении».

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