(Mongo/Mongoose) 如何处理等待多个查询的结果

Posted

技术标签:

【中文标题】(Mongo/Mongoose) 如何处理等待多个查询的结果【英文标题】:(Mongo/Mongoose) How to handle waiting for the result of multiple queries 【发布时间】:2020-07-24 16:12:12 【问题描述】:

我正在编写一个 Discord 机器人,它会为文本和语音频道的使用情况生成每周公会统计数据。我的代码将几个 Mongo 查询分成不同的方法:

function getTopActiveTextChannels() 
  let topTextChannels = []
  ChannelModel.find().sort("messageCountThisWeek": -1).limit(topLimit)
   .exec(channels => 
    channels.forEach(c => 
      topTextChannels.push("name": c.name, "messageCount": c.messageCount)
    )
    console.log(topTextChannels)
    return topTextChannels
  )


function getTopActiveVoiceMembers() 
  let topVoiceMembers = []
  UserModel.find().sort("timeSpentInVoice": -1).limit(topLimit)
  .exec(users => 
    users.forEach(u => 
      topVoiceMembers.push("username": u.username, "timeSpentInVoice": u.timeSpentInVoice)
    )
    console.log(topVoiceMembers)
    return topVoiceMembers
  )

然后我有一种方法可以同时调用它们,并且(现在)将值打印到控制台:

function getWeeklyGuildStats(client) 
  let topActiveTextChannels = getTopActiveTextChannels()
  let topVoiceMembers = getTopActiveVoiceMembers()
  let promisesArray = [topActiveTextChannels, topVoiceMembers]

  Promise.all(promisesArray).then(values => console.log(values))

执行getWeeklyGuildStats(client) 输出:[ undefined, undefined ]。我确定我没有正确使用 Promise,但是当我按照 Mongoose 的文档进行操作时,它告诉我使用 exec() 而不是 then(),但我得到了 channels = null 错误。

有什么东西会跳出来吗?这似乎是一个相当普遍的模式。有没有人可以解决如何在一个方法中解决多个 Mongoose 查询?

【问题讨论】:

【参考方案1】:

Promise.all 应该接受一个 promise 数组,而你的函数返回的是普通数组,所以你需要在获取用户和频道的辅助方法中返回整个查询,然后在 promise.all

你的函数可能看起来像这样

function getTopActiveTextChannels() 
  return ChannelModel.find().sort("messageCountThisWeek": -1).limit(topLimit).exec();


function getTopActiveVoiceMembers() 
  return UserModel.find().sort("timeSpentInVoice": -1).limit(topLimit).exec();

那么调用这两个方法的函数将类似于

function getWeeklyGuildStats(client) 
  let topActiveTextChannels = getTopActiveTextChannels()
  let topVoiceMembers = getTopActiveVoiceMembers()
  let promisesArray = [topActiveTextChannels, topVoiceMembers]

  Promise.all(promisesArray).then(values => 
     console.log(values);
     // here you could do your own logic, the for loops you did in the helper methods before
  );

【讨论】:

好的,将参数修改为Promise.all() 为方法调用。仍然得到输出[ undefined, undefined ] 你能在查询完成后尝试 console.log 用户和频道吗?我的意思是在 .then 之后在 getTopActiveVoiceMembers 函数中记录用户,对于频道也是如此? 我在每个方法的返回值之前添加了console.log 语句。 topTextChannelstopVoiceMembers 都在打印正确的数据。 我已经编辑了我的答案,你现在可以检查一下吗?希望它现在有帮助 我重新组织了查找方法以返回 Mongoose 承诺,并将 .then() 逻辑移动到单独的辅助方法,我从主方法调用。谢谢,成功了!【参考方案2】:

您的函数的根级别中没有任何返回语句,因此它们总是同步返回undefined。我不熟悉您正在使用的库,但是如果例如 ChannelModel.find().exec(callback) 返回一个返回值为 callback 的承诺,正如您的代码所暗示的那样,那么您只需要在您的函数中添加一个 return 语句.

例如:

function getTopActiveTextChannels() 
  let topTextChannels = []
  // Return this! (Assuming it returns a promise.) Otherwise you're always returning `undefined`.
  return ChannelModel.find().sort("messageCountThisWeek": -1).limit(topLimit)
   .exec(channels => 
    channels.forEach(c => 
      topTextChannels.push("name": c.name, "messageCount": c.messageCount)
    )
    console.log(topTextChannels)
    return topTextChannels
  )

【讨论】:

以上是关于(Mongo/Mongoose) 如何处理等待多个查询的结果的主要内容,如果未能解决你的问题,请参考以下文章

如何处理:循环调用'Thread.sleep()',可能是忙等待

等待/异步如何处理未解决的承诺

如何处理我的 AWS EC2 实例上的多个 Python 请求?

如何处理异步/等待获取 API 中的错误 404

Flutter 如何处理异步/等待中的错误

net/http:请求已取消(等待标头时超出 Client.Timeout)为啥/如何处理?