NodeJS - 控制器 - 来自集合+ forEach的多个查询

时间:2018-05-05 12:43:38

标签: javascript node.js asynchronous mongoose promise

搞乱承诺和异步& amp;等待。想得到你的建议,以下控制器案例的最佳做法是什么?现在它在将数据传递给客户端之前不会获得用户详细信息。

我正在使用NodeJS为服务器端做一个简单的API端点。 Controller正在进行两个查询以完成简单的结果作为客户端的json对象。是的,这个无用的run []数组,但在构建整个事件结果时使用它:)

exports.runresults3 = function(req, res) {

  // Route is passing ID
  console.log('id', req.params.id);

  // Test results object to fill
  const resultsParams = {
    run: [{
      runid: {},
      endtimeid: [],
      userid: [],
      endtime: [],
      username: [],
    }]
  }

  // Run objectid
  resultsParams.run[0].runid = req.params.id;

  // Get the endtimes by location/stage
  Endtime.find({stage: req.params.id})
    .then(data => {
      // First loop
      data.forEach(value => {
        resultsParams.run[0].endtimeid.push(value._id);
        resultsParams.run[0].userid.push(value.user);
        resultsParams.run[0].endtime.push(value.endtime);
      })
    })
    .then(() => {
      // Second loop to get user details for results object
      resultsParams.run[0].userid.forEach((userId, i) => {
        TempUser.findById(userId)
          .then(userdetails => {
            console.log('userdetails.name', userdetails.name);
            resultsParams.run[0].username.push(userdetails.name);
          });
      })
    })
    .then(() => {
      res.json(resultsParams);
    });
}

////////////客户端将获得如下json

{
"run": [
    {
        "runid": "5ae850d51717862590dc30d4",
        "endtimeid": [
            "5aec482d98555332145eccd3",
            "5aec48c098555332145eccd6",
            "5aec4a2c98555332145eccda",
            "5aec4ab398555332145eccdd",
            "5aec4bb998555332145ecce1",
            "5aec4e42c3bcbb196c8474fc",
            "5aec4e44c3bcbb196c8474fe",
            "5aec4e45c3bcbb196c847500"
        ],
        "userid": [
            "5aec13b098555332145eccbe",
            "5ae869c797e54a37f498c98f",
            "5aec4a1298555332145eccd7",
            "5aec4a1298555332145eccd7",
            "5aec4ba698555332145eccde",
            "5aec13a598555332145eccbc",
            "5ae869c797e54a37f498c98f",
            "5aec13b098555332145eccbe"
        ],
        "endtime": [
            24424,
            3280,
            11858,
            38874,
            5738,
            40384,
            50906,
            36717
        ],
        "username": []
    }
]

}

2 个答案:

答案 0 :(得分:0)



exports.runresults3 = function(req, res) {

  // Route is passing ID
  console.log('id', req.params.id);

  // Test results object to fill
  const resultsParams = {
    run: [{
      runid: {},
      endtimeid: [],
      userid: [],
      endtime: [],
      username: [],
    }]
  }

  // Run objectid
  resultsParams.run[0].runid = req.params.id;

  Endtime.find({stage: req.params.id})
    .then(data => {
      return Promise.all(data.map(record => {
        TempUser.findById(record.user)
          .then(userdetails => {
            return {
              endtimeid: record._id,
              userid: record.user,
              endtime: record.endtime,
              username: userdetails.name
            };
          })
      }))
      .then(detailRecords => {
        return detailRecords.reduce((acc, curr) => {
          acc.endtimeid.push(curr.endtimeid);
          acc.userid.push(curr.userid);
          acc.endtime.push(curr.endtime);
          acc.username.push(curr.username);
          return acc;
        },resultsParams.run[0]);
      })
      .then(() => {
        res.json(resultsParams);
      });
    });
}




如果您需要将事物积累到"关联数组"这个结果对象中的事物风格,这可能就是我这样做的方式。

话虽如此,我很可能会尝试将事物作为一系列运行结果返回 - 更像是以下内容......

{
  "run": [
    {
      "runid": "5ae850d51717862590dc30d4",
      "results": [
        {
          "endtimeid": "5aec482d98555332145eccd3",
          "userid": "5aec13b098555332145eccbe",
          "endtime": 24424,
          "username": "User123"
        },
        {
          "endtimeid": "5aec48c098555332145eccd6",
          "userid": "5ae869c797e54a37f498c98f",
          "endtime": 3280,
          "username": "User234"
        }
      ]
    }
  ]
}

我相信以下代码应该这样做。



exports.runresults3 = function(req, res) {

  // Route is passing ID
  console.log('id', req.params.id);

  // Test results object to fill
  const resultsParams = {
    run: [{
      runid: {},
      results: []
    }]
  }

  // Run objectid
  resultsParams.run[0].runid = req.params.id;

  Endtime.find({stage: req.params.id})
    .then(data => {
      return Promise.all(data.map(record => {
        TempUser.findById(record.user)
          .then(userdetails => {
            return {
              endtimeid: record._id,
              userid: record.user,
              endtime: record.endtime,
              username: userdetails.name
            };
          })
      }))
    })
    .then(results => resultsParams.run[0].results = reuslts)
    .then(() => res.json(resultsParams));
}




当然可以有更多的可读性重构,并且填充结果的最后一步没有使用前一个流程的结果会让我感到麻烦 - 但我尽量避免副作用可能,所以这可能只是我。

答案 1 :(得分:0)

以下是经过编辑的版本,但仍然缺少用户详细信息,看起来像promise.all isnt waiting" TempUser.findById(record.user)"查询。

1我创建了一个新事件,运行,3个用户和3个结果。

2然后我在db调用

中设置了一些日志

3然后我跟邮递员提出了一个请求

在Postman GET请求之后,从localhost的日志看起来像这样:

$ node app 服务器启动5000 Mongodb连接 id 5aeebd8a1b5ddf1424c25194

  1. 从数据库中获取结束时间
  2. [{created:2018-05-06T08:32:46.359Z,     _id:5aeebdae1b5ddf1424c25199,     结束时间:23204,     用户:5aeebd751b5ddf1424c25191,     阶段:5aeebd8a1b5ddf1424c25194,     __v:0},   {创建时间:2018-05-06T08:32:49.414Z,     _id:5aeebdb11b5ddf1424c2519b,     结束时间:17149,     用户:5aeebd7b1b5ddf1424c25192,     阶段:5aeebd8a1b5ddf1424c25194,     __v:0},   {创建时间:2018-05-06T08:32:51.769Z,     _id:5aeebdb31b5ddf1424c2519d,     结束时间:10840,     用户:5aeebd7f1b5ddf1424c25193,     阶段:5aeebd8a1b5ddf1424c25194,     __v:0}]

    1. 将结果设置为对象
    2. [未定义,未定义,未定义] 这应该是链中的最后一个?

      1. 从数据库中获取用户详细信息
      2. {date:2018-05-06T08:31:49.673Z,   _id:5aeebd751b5ddf1424c25191,   名称:' Firstame姓氏1',   __v:0} 2.从数据库获取用户详细信息{date:2018-05-06T08:31:55.562Z,   _id:5aeebd7b1b5ddf1424c25192,   名称:' Firstame姓氏2',   __v:0} 2.从数据库获取用户详细信息{date:2018-05-06T08:31:59.906Z,   _id:5aeebd7f1b5ddf1424c25193,   名称:' Firstame姓氏3',   __v:0}

        这是通过以下代码完成的:

        
        
        exports.runresults3 = function(req, res) {
        
          // Route is passing ID
          console.log('id', req.params.id);
          
          // Test results object to fill
          const resultsParams = {
            run: [{
              runid: {},
              results: []
            }]
          }
        
          // Each run objectid
          resultsParams.run[0].runid = req.params.id;
        
          Endtime.find({stage: req.params.id})
            .then(data => {
              console.log('1. Get endtimes from database', data);
              return Promise.all(data.map(record => {
                TempUser.findById(record.user)
                  .then(userdetails => {
                    console.log('2. Get user details from database', userdetails);
                    return {
                      endtimeid: record._id,
                      userid: record.user,
                      endtime: record.endtime,
                      username: userdetails.name
                    };
                  })
              }))
            })
            .then(results => { 
              console.log('3. Set results to object', results);
              console.log('This should be the last one at chain?');
              
              resultsParams.run[0].results = results;
            })
            .then(() => res.json(resultsParams));
        }