NodeJS - 控制器 - 来自集合的多个查询 + forEach
Posted
技术标签:
【中文标题】NodeJS - 控制器 - 来自集合的多个查询 + forEach【英文标题】:NodeJS - controller - multiple queries from collections + forEach 【发布时间】:2018-10-15 19:21:06 【问题描述】:对 promises 和 async & await 感到困惑。想听听您的建议,以下控制器案例的最佳实践是什么?现在它在将数据传递给客户端之前不会获取用户详细信息。
我正在使用 NodeJS 为服务器端做一个简单的 API 端点。控制器正在进行两个查询以完成简单的结果作为客户端的 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": []
]
【问题讨论】:
您在resultsParams.run[0].userid.forEach
之前的第二个then
中缺少return
,并且.forEach
需要是.map
和Promise.all
,所以它知道等待所有结果。
作为一个快速的澄清点,是否期望数组中的行在所有 3 个数组中的顺序相同?每个结果都有一个对象数组而不是数组数组更有意义吗?
@BenjaminGruenbaum 感谢您的回复,但还没有完全奏效。用户详细信息终于来了,所以数据已经传递给客户端.. CodyKnapp,是的,你是对的,那更干净
我只是改变了整个结果概念。现在它在保存它们时正在准备好结果,因此在通过单个运行 id 提取结果时不需要进行复杂的查询。这让我觉得即使它是一个 mvp 应用程序。 :) 目前不需要帮助!谢谢你们的cmets!!!
【参考方案1】:
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));
当然可以进行更多的可读性重构,而且填充结果的最后一步不使用前一个流程的结果这一事实让我有点困扰 - 但我尽量避免副作用,所以这可能就是我。
【讨论】:
【参考方案2】:这是建议的编辑版本 :) 但仍然缺少用户详细信息,看起来 promise.all 没有等待“TempUser.findById(record.user)”查询。
1 我创建了一个新事件,运行,3 个用户和 3 个结果。
2 然后我在数据库调用中设置了一些日志
3 然后我用邮递员做了一个get请求
在 Postman GET 请求后来自 localhost 的日志如下所示:
$ 节点应用程序 服务器启动于 5000 连接MongoDB 编号 5aeebd8a1b5ddf1424c25194
-
从数据库中获取结束时间
[ 创建时间: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 ]
-
将结果设置为对象
[未定义,未定义,未定义] 这应该是链上的最后一个?
-
从数据库中获取用户详细信息
日期:2018-05-06T08:31:49.673Z, _id: 5aeebd751b5ddf1424c25191, name: 'Firstname Lastname1', __v: 0 2.从数据库中获取用户详细信息日期:2018-05-06T08:31:55.562Z, _id: 5aeebd7b1b5ddf1424c25192, name: 'Firstname Lastname2', __v: 0 2. 从数据库中获取用户详细信息 date: 2018-05-06T08:31:59.906Z, _id: 5aeebd7f1b5ddf1424c25193, name: 'Firstname Lastname3', __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));
【讨论】:
以上是关于NodeJS - 控制器 - 来自集合的多个查询 + forEach的主要内容,如果未能解决你的问题,请参考以下文章
如何防止 DataGrip 显示来自另一个查询控制台的结果?
使用来自 Nodejs Postgres 查询的数据 [重复]