1

我正在尝试在 NodeJS 应用程序中将所有 Redis 密钥与 MongoDB 同步。

我使用 ioredis 作为 NodeJS Redis 客户端,并尝试通过使用scanStream() 函数来实现上述目的。这个函数被认为是一种使用流扫描光标中所有键的更简单方法。

这是我用来尝试扫描所有键的代码:

const stream = await redis.scanStream();
stream.on("data", async (resultKeys) => {
  await stream.pause();
  for (let i = 0; i < resultKeys.length; i++) {
    try {
      let KEY = resultKeys[i];
      let redisObjectStr = await redis.get(KEY);
      let redisObject = JSON.parse(redisObjectStr);

      // Sync Redis key with MongoDB
      const user = await User.findOne({
        apiKey: KEY
      }).exec();

      if (user) {
        user.color = redisObject.color;
        user.size = redisObject.size;
        await user.save();
        await stream.resume();
      }
    } catch (err) {
      next(err)
    }
  }
});
stream.on("end", () => {
  console.log("all keys have been visited")
  res.send("done")
})

但是我收到以下错误:

api_1 | 所有键都已访问 proxy_1 | 172.18.0.1 - - [22/Jan/2019:12:52:06 +0000] "GET /api/syncredis HTTP/1.1" 200 4 "-" "PostmanRuntime/7.6.0" "-" api_1 | ::ffff:172.18.0.6 - - [22/Jan/2019:12:52:06 +0000] "GET /api/syncredis HTTP/1.1" 200 4 "-" "PostmanRuntime/7.6.0" api_1 | SyntaxError: 位置 0 api_1 处 JSON 中的意外标记 l | 在 JSON.parse() api_1 | 在 ScanStream.stream.on (/usr/src/app/routes/testRoute.js:428:32) api_1 | 在 process.internalTickCallback (internal/process/next_tick.js:77:7) api_1 | 错误 [ERR_HTTP_HEADERS_SENT]:在将标头发送到客户端后无法设置标头

4

1 回答 1

3

我假设您使用的是简单的 redis 而不是集群的。您应该尝试将其包装在一个 Promise 中,以便它直接跳转到 stream.end 并检查您从 redis.get 获得的结果,检查它是否是一个正确的可解析 json 字符串。

我建议从不同的函数中获取所有键,然后迭代所有与 mongo 同步的键。

代码 :-

let arrOfKeys = await getKeys(prefix);
//loop through all the keys and sync with mongo 

const getKeys = async (prefix = "") => {
    let finalKeyArray = [], keysArray = [];
    let stream = redis.scanStream({
        match: prefix
    });
    return new Promise((res, rej) => {
        stream.on("data", async (keys = []) => {
            let key;
            for (key of keys) {
                if (!keysArray.includes(key)) {
                    await keysArray.push(key);
                }
            }
        });
        stream.on("end", () => {
            res(keysArray);
        });
    }).then((keysets) => {
        keysets.forEach((keySet) => {
            keySet.forEach((key) => {
                if (!finalKeyArray.includes(key)) {
                    finalKeyArray.push(key);
                }
            })
        })
        return finalKeyArray;
    }).catch((err) => {
        console.error("Error while getting redis keys:", err);
        return [];
    });
}
于 2020-08-19T07:26:06.190 回答