использование заселения с сохранением с помощью async ждут в мангусте [дубликат]

Вместо того, чтобы бросать код на вас, есть два понятия, которые являются ключом к пониманию того, как JS обрабатывает обратные вызовы и асинхронность. (это даже слово?)

Модель цикла события и параллелизма

Есть три вещи, о которых вам нужно знать; Очередь; цикл события и стек

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

while (queue.waitForMessage()) {
   queue.processNextMessage();
}

Как только он получает сообщение для запуска чего-то, он добавляет его в очередь. Очередь - это список вещей, которые ждут выполнения (например, ваш запрос AJAX). Представьте себе это так:

 1. call foo.com/api/bar using foobarFunc
 2. Go perform an infinite loop
 ... and so on

Когда одно из этих сообщений будет исполнено, оно выталкивает сообщение из очереди и создает стек, стек - это все, что нужно выполнить JS для выполнения инструкции в сообщение. Таким образом, в нашем примере ему говорят позвонить foobarFunc

function foobarFunc (var) {
  console.log(anotherFunction(var));
}

. Так что все, что foobarFunc должно выполнить (в нашем случае anotherFunction), будет вставлено в стек. исполняемый, а затем забытый - цикл события затем переместится на следующую вещь в очереди (или прослушивает сообщения)

. Главное здесь - порядок выполнения. Это

КОГДА что-то будет запущено

Когда вы совершаете вызов с использованием AJAX для внешней стороны или выполняете любой асинхронный код (например, setTimeout), Javascript зависит от ответ, прежде чем он сможет продолжить.

Большой вопрос, когда он получит ответ? Ответ в том, что мы не знаем, поэтому цикл событий ждет, когда это сообщение скажет: «Эй, забери меня». Если JS просто ждал этого сообщения синхронно, ваше приложение замерзнет, ​​и оно сосать. Таким образом, JS продолжает выполнение следующего элемента в очереди, ожидая, пока сообщение не будет добавлено обратно в очередь.

Вот почему с асинхронной функциональностью мы используем вещи, называемые обратными вызовами. Это похоже на обещание буквально. Как и в I , обещание что-то вернуть в какой-то момент jQuery использует специальные обратные вызовы, называемые deffered.done deffered.fail и deffered.always (среди других). Вы можете увидеть их все здесь

Итак, вам нужно передать функцию, которая в какой-то момент будет выполнена с переданными ей данными.

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

function foo(bla) {
  console.log(bla)
}

, поэтому большую часть времени (но не всегда) вы пройдете foo не foo()

. Надеюсь, это будет иметь смысл. Когда вы сталкиваетесь с такими вещами, которые кажутся запутанными, я настоятельно рекомендую полностью прочитать документацию, чтобы хотя бы понять ее. Это сделает вас намного лучшим разработчиком.

59
задан Pykler 19 January 2015 в 18:14
поделиться

9 ответов

Вы должны иметь возможность использовать функцию заполнения модели для этого: http://mongoosejs.com/docs/api.html#model_Model.populate В обработчике сохранения для книги вместо :

book._creator = user;

вы бы сделали что-то вроде:

Book.populate(book, {path:"_creator"}, function(err, book) { ... });

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

111
ответ дан user1417684 4 September 2018 в 08:06
поделиться

Я подумал, что добавлю к этому, чтобы прояснить ситуацию для полных нубов, подобных мне.

Что сильно запутывает, если вы не внимательны, так это три разных метода заполнения. Они - методы разных объектов (Model vs. Document), принимают разные входы и дают разные выходы (Document vs. Promise).

Здесь они предназначены для тех, кто сбиты с толку:

Document.prototype.populate ()

См. Полный документ.

Этот файл работает с документами и возвращает документ. В исходном примере это будет выглядеть так:

book.save(function(err, book) {
    book.populate('_creator', function(err, book) {
        // Do something
    })
});

Поскольку он работает с документами и возвращает документ, вы можете связать их следующим образом:

book.save(function(err, book) {
    book
    .populate('_creator')
    .populate('/* Some other ObjectID field */', function(err, book) {
        // Do something
    })
});

Но не будьте глупыми, как я, и попытайтесь сделать это:

book.save(function(err, book) {
    book
    .populate('_creator')
    .populate('/* Some other ObjectID field */')
    .then(function(book) {
        // Do something
    })
});

Помните: Document.prototype.populate () возвращает документ, поэтому это вздор. Если вам нужно обещание, вам нужно ...

Document.prototype.execPopulate ()

См. Полный документ.

Это работает над документами, но возвращает обещание, которое разрешает документ. Другими словами, вы можете использовать его следующим образом:

book.save(function(err, book) {
    book
    .populate('_creator')
    .populate('/* Some other ObjectID field */')
    .execPopulate()
    .then(function(book) {
        // Do something
    })
});

Это лучше. Наконец, есть ...

Model.populate ()

См. Полные документы.

Это работает на моделях и возвращается Обещание. Поэтому он используется несколько иначе:

book.save(function(err, book) {
    Book // Book not book
    .populate(book, { path: '_creator'})
    .then(function(book) {
        // Do something
    })
});

Надеюсь, что это помогло другим новичкам.

2
ответ дан curzmg 4 September 2018 в 08:06
поделиться

В случае, если кто-то все еще ищет это.

Mongoose 3.6 представила множество интересных функций для заполнения:

book.populate('_creator', function(err) {
 console.log(book._creator);
});

или:

Book.populate(book, '_creator', function(err) {
 console.log(book._creator);
});

подробнее см .: https://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#population

Но таким образом вы все равно будете запрашивать для пользователя снова.

Небольшой трюк для выполнения этого без дополнительных запросов будет:

book = book.toObject();
book._creator = user;
29
ответ дан Eric Saboia 4 September 2018 в 08:06
поделиться

Решение для меня заключалось в использовании execPopulate, например

const t = new MyModel(value)
return t.save().then(t => t.populate('my-path').execPopulate())
4
ответ дан François Romain 4 September 2018 в 08:06
поделиться

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

https://github.com/LearnBoost/mongoose/issues/570

Что вы можете сделать, это написать собственный пользовательский getter / setter (и установить real _customer в отдельном свойстве) для этого. Например:

var get_creator = function(val) {
    if (this.hasOwnProperty( "__creator" )) {
        return this.__creator;
    }
    return val;
};
var set_creator = function(val) {
    this.__creator = val;
    return val;
};
var bookSchema = new mongoose.Schema({
  _creator: {
     type: mongoose.Schema.Types.ObjectId,
     ref: 'User',
     get: get_creator,
     set: set_creator
  },
  description: String,
});

ПРИМЕЧАНИЕ. Я не тестировал его, и он мог бы работать странно с .populate и при установке чистого идентификатора.

1
ответ дан freakish 4 September 2018 в 08:06
поделиться

Решение, которое возвращает обещание (нет обратных вызовов):

Использовать документ # populate

book.populate('creator').execPopulate();

// summary
doc.populate(options);               // not executed
doc.populate(options).execPopulate() // executed, returns promise

Возможная реализация

var populatedDoc = doc.populate(options).execPopulate();
var populatedDoc.then(doc => {
   ... 
});

здесь .

6
ответ дан Govind Rai 4 September 2018 в 08:06
поделиться

Вероятно, шт. например

Book.createAsync(bookToSave).then((savedBook) => savedBook.populateAsync("creator"));

Было бы самым приятным и наименее проблематичным способом сделать эту работу (используя обещания Bluebird).

0
ответ дан kboom 4 September 2018 в 08:06
поделиться

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

  post.save(function(err) {
    if (err) {
      return res.json(500, {
        error: 'Cannot save the post'
      });
    }
    post.populate('group', 'name').populate({
      path: 'wallUser',
      select: 'name picture'
    }, function(err, doc) {
      res.json(doc);
    });
  });
11
ответ дан Pratik Bothra 4 September 2018 в 08:06
поделиться

Mongoose 5.2.7

Это работает для меня (просто много головной боли!) [/ ​​g1]

exports.create = (req, res, next) => {
  const author = req.userData;
  const postInfo = new Post({
    author,
    content: req.body.content,
    isDraft: req.body.isDraft,
    status: req.body.status,
    title: req.body.title
  });
  postInfo.populate('author', '_id email role display_name').execPopulate();
  postInfo.save()
    .then(post => {
      res.status(200).json(post);
    }).catch(error => {
      res.status(500).json(error);
    });
};
0
ответ дан Whisher 4 September 2018 в 08:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: