node.js - 如何使猫鼬更新与等待一起工作?
问题描述
我正在创建一个 NodeJS 后端,其中一个进程从源读取数据,检查与当前数据相比的更改,对 MongoDB 进行这些更新并报告所做的更改。一切正常,除了我无法报告更改,因为我无法等待 Mongoose 更新操作。
这个函数返回的数组然后由 Koa 服务器显示。它显示一个空数组,并且在服务器日志中,服务器返回空响应后会出现正确的值。
我已经深入研究了 Mongoose 文档和 Stack Overflow 问题——关于这个主题的很多问题——但没有成功。提供的解决方案似乎都没有帮助。我已将问题隔离到这一部分:如果我删除 Mongoose 部分,一切都会按预期工作。
const parseJSON = async xmlData => {
const changes = []
const games = await Game.find({})
const gameObjects = games.map(game => {
return new GameObject(game.name, game.id, game)
})
let jsonObj = require("../sample.json")
Object.keys(jsonObj.items.item).forEach(async item => {
const game = jsonObj.items.item[item]
const gameID = game["@_objectid"]
const rating = game.stats.rating["@_value"]
if (rating === "N/A") return
const gameObject = await gameObjects.find(
game => game.bgg === parseInt(gameID)
)
if (gameObject && gameObject.rating !== parseInt(rating)) {
try {
const updated = await Game.findOneAndUpdate(
{ _id: gameObject.id },
{ rating: rating },
{ new: true }
).exec()
changes.push(
`${updated.name}: ${gameObject.rating} -> ${updated.rating}`
)
} catch (error) {
console.log(error)
}
}
})
return changes
}
一切正常——发现更改并更新数据库,但报告的更改返回得太晚,因为执行不等待 Mongoose。
我也试过这个而不是findOneAndUpdate()
:
const updated = await Game.findOne()
.where("_id")
.in([gameObject.id])
.exec()
updated.rating = rating
await updated.save()
这里的结果相同:其他一切都有效,但异步没有。
解决方案
map
正如@Puneet Sharma 所提到的,您必须forEach
先获得一系列承诺,然后await
在返回之前获得承诺(Promise.all
为了方便起见)changes
,然后将其填充:
const parseJSON = async xmlData => {
const changes = []
const games = await Game.find({})
const gameObjects = games.map(game => {
return new GameObject(game.name, game.id, game)
})
const jsonObj = require("../sample.json")
const promises = Object.keys(jsonObj.items.item).map(async item => {
const game = jsonObj.items.item[item]
const gameID = game["@_objectid"]
const rating = game.stats.rating["@_value"]
if (rating === "N/A") return
const gameObject = await gameObjects.find(
game => game.bgg === parseInt(gameID)
)
if (gameObject && gameObject.rating !== parseInt(rating)) {
try {
const updated = await Game.findOneAndUpdate(
{ _id: gameObject.id },
{ rating: rating },
{ new: true }
).exec()
changes.push(
`${updated.name}: ${gameObject.rating} -> ${updated.rating}`
)
} catch (error) {
console.log(error)
}
}
})
await Promise.all(promises)
return changes
}
(差异,为方便起见:
9,10c9,10
< let jsonObj = require("../sample.json")
< Object.keys(jsonObj.items.item).forEach(async item => {
---
> const jsonObj = require("../sample.json")
> const promises = Object.keys(jsonObj.items.item).map(async item => {
33a34
> await Promise.all(promises)
)
编辑:进一步的重构是使用该系列的承诺来进行更改描述本身。基本上changePromises
是一个Promise
解析为字符串或 null 的数组(如果没有更改),因此.filter
带有标识函数的 a 将过滤掉虚假值。
此方法还有一个优点,即changes
与键的迭代顺序相同;使用原始代码,无法保证顺序。这对您的用例可能很重要,也可能无关紧要。
我还翻转了map
函数中的 if/else 以减少嵌套;这真的是品味问题。
附言。await Game.find({})
当您拥有大量游戏时,这将是一个问题。
const parseJSON = async xmlData => {
const games = await Game.find({});
const gameObjects = games.map(game => new GameObject(game.name, game.id, game));
const jsonGames = require("../sample.json").items.item;
const changePromises = Object.keys(jsonGames).map(async item => {
const game = jsonGames[item];
const gameID = game["@_objectid"];
const rating = game.stats.rating["@_value"];
if (rating === "N/A") {
// Rating from data is N/A, we don't need to update anything.
return null;
}
const gameObject = await gameObjects.find(game => game.bgg === parseInt(gameID));
if (!(gameObject && gameObject.rating !== parseInt(rating))) {
// Game not found or its rating is already correct; no change.
return null;
}
try {
const updated = await Game.findOneAndUpdate(
{ _id: gameObject.id },
{ rating: rating },
{ new: true },
).exec();
return `${updated.name}: ${gameObject.rating} -> ${updated.rating}`;
} catch (error) {
console.log(error);
}
});
// Await for the change promises to resolve, then filter out the `null`s.
return (await Promise.all(changePromises)).filter(c => c);
};
推荐阅读
- entity-framework - 我无法在 .NET Core 3.1.9 中使用实体框架创建新的 Web API
- r - 正态混合分布
- python - 在 Python 中以递归方式返回由列表表示的树的节点
- cryptography - 保存使用用户密码加密的私钥是否比在数据库中存储哈希更安全?
- pandas - 根据其他列中的条件替换值
- directx - 为什么每次 OpenSharedResource 调用都会导致显存增加(泄漏)?
- r - 创建 df 时:对于一列,仅在特定行中添加值
- c - 如何使用纯 C 的指针设计函数
- docker - 如何将 rpm 安装到 /usr/bin 而不是 /opt/app-root/bin
- flutter - 如何删除 Cloud Firestore 中除一个之外的所有文档?