Pu sh mon goose результаты запроса к глобальному массиву - PullRequest
0 голосов
/ 26 мая 2020

Я пытаюсь использовать mon goose для запроса моих коллекций mongodb, но результаты не отображаются. Думаю, я знаю почему, потому что что-то, что-то, async / wait / prom, но ничего не работает. Обычно мне нужны 2 запроса, один для извлечения объекта, указанного в запрошенной ссылке (идентификатор рабочего процесса), который сам имеет несколько «шагов», на которые есть ссылки в массиве идентификаторов объектов. Они не передаются в переменную с областью действия (workflowStepCombined). Запрос работает так, как задумано, если я регистрирую результаты внутри forEach, я получаю именно то, что ожидал. Как я уже упоминал, я считаю, что проблема в том, что приложение не ждет результатов, я несколько раз прочитал mon goose do c с обещаниями и реализовал то, что я считаю решением, однако после рефакторинга весь день без прогресса.

app.get("/new/:workflowID", function (req, res) {
  if (req.isAuthenticated()) {
    const workflowID = req.params.workflowID;
    //define array to push recombined steps to
    let workflowStepCombined = [];
    Workflow.findOne({ workflowName: workflowID }, function (err,foundWorkflow) {
        const stepsArray = foundWorkflow.workflowStepArray;
        //once workflow found, start pulling from step collection the listed IDs
        stepsArray.forEach(function (step) {
          Steps.findOne({ _id: step }, (err, foundStep) => {
              //push to array that was definedin first part
              workflowStepCombined.push(foundStep);
          });
        });
        //render it all together
        res.render("contracts/" + workflowID, {
          userID: req.user.username,
          workflow: workflowStepCombined,
        });
      }); 
    } else {
        res.redirect("/");
        }
    });

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

app.get("/new/:workflowID", function (req, res) {
  if (req.isAuthenticated()) {
      //allows for dynamic link creation
    const workflowID = req.params.workflowID;
    const stepsArray = [];
    //define array to push recombined steps to
    let workflowStepCombined = [];

    //find workflow with name from link
    Workflow.findOne({ workflowName: workflowID }).then(foundWorkflow => {
      stepsArray.push(foundWorkflow.workflowStepArray);
    })
    console.log(stepsArray)
    //once workflow found, start pulling from step collection the listed IDs
    stepsArray.forEach(function (step) {
    Steps.findOne({ _id: step }).then(foundStep => {
        workflowStepCombined.push(foundStep);
        console.log(foundStep);
     });
    });
      //render it all together
      res.render("contracts/" + workflowID, {
        userID: req.user.username,
        workflow: workflowStepCombined,
      });

Ответы [ 2 ]

0 голосов
/ 26 мая 2020

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

stepsArray.forEach(function (step) {
  Steps.findOne({ _id: step }, (err, foundStep) => {
      //push to array that was definedin first part
      workflowStepCombined.push(foundStep);
  });
});

Array.forEach сложно с асинхронными обратными вызовами, в вашем случае вы ожидаете, что каждый l oop будет выполняться и разрешаться до следующего, так что при конец l oop, результат всех запросов findOne будет в массиве workflowStepCombined, однако это не так, вы можете проверить эту статью, чтобы узнать, почему .

Простым исправлением было бы использовать Promise.all следующим образом:

Promise.all(stepsArray.map(stepId => Steps.findOne({_id: stepId})))
  .then(workflowStepCombined => {
    res.render("contracts/" + workflowID, {
      userID: req.user.username,
      workflow: workflowStepCombined,
    });
  })

Однако, поскольку sepsArray представляет собой массив шагов рабочего процесса _id s, вы можете сделать использование одного поискового запроса вместо выполнения нескольких запросов в al oop. Примерно так:

Steps.find({ _id: { $in: stepsArray } })

Это должно вернуть массив, содержащий все объекты step, указанные в stepsArray, поэтому нет необходимости в l oop и pu sh. В сочетании с предыдущим запросом конечная точка должна быть примерно такой:

app.get("/new/:workflowID", function (req, res) {
  if (req.isAuthenticated()) {
    const workflowID = req.params.workflowID;

    Workflow.findOne({ workflowName: workflowID }, function (err,foundWorkflow) {
        const stepsArray = foundWorkflow.workflowStepArray;

        Steps.find({ _id: { $in: stepsArray } }, function(error, workflowStepCombined) {

          res.render("contracts/" + workflowID, {
            userID: req.user.username,
            workflow: workflowStepCombined,
          });

        })
      }); 
    } else {
        res.redirect("/");
        }
    });

Не забывайте перехватывать и обрабатывать возможные ошибки

0 голосов
/ 26 мая 2020
Функция

forEach не является asyn c, поэтому вы вызываете res.render перед получением результата шагов. Вы должны использовать функцию Promise.all

Promise.all(stepsArray.map(step => Steps.findOne({ _id: step })))
  .then(workflowStepCombined => {
    return  res.render("contracts/" + workflowID, {
      userID: req.user.username,
      workflow: workflowStepCombined,
    });
  })

Я предлагаю вам использовать подход async / await вместо обратных вызовов

app.get("/new/:workflowID", async (req, res) => {
  if (req.isAuthenticated()) {
    const workflowID = req.params.workflowID;
    //define array to push recombined steps to
    let workflowStepCombined = [];
    const workflow = await Workflow.findOne({ workflowName: workflowID });
    const stepsArray = foundWorkflow.workflowStepArray;
    const workflowSteps = await Steps.find({_id: {$in: stepsArray}}) //https://docs.mongodb.com/manual/reference/operator/query/in/ and you could use sort here if needed - https://mongoosejs.com/docs/api.html#model_Model.find

    //render it all together
    res.render("contracts/" + workflowID, {
      userID: req.user.username,
      workflow: workflowSteps,
    });
  } else {
    res.redirect("/");
  }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...