【问题标题】:Mongoose - How to return counts of two different things?Mongoose - 如何返回两种不同事物的计数?
【发布时间】:2020-08-10 22:01:46
【问题描述】:

我对 MongoDB 和 Mongoose 非常陌生,似乎发现自己需要一个相当复杂的查询。我的架构如下。

const gameSchema = new mongoose.Schema({
    _winnerId: {
        type: mongoose.Schema.Types.ObjectId,
        required: true,
        ref: 'User',
    },
    _loserId: {
        type: mongoose.Schema.Types.ObjectId,
        required: true,
        ref: 'User',
    },
    winnerWords: [String],
    loserWords: [String],
}); 

我正在尝试获取给定用户 ID 的赢/输比率。不知何故,我需要计算用户 ID 作为 _winnerId 出现的次数以及用户 ID 作为 _loserId 出现的次数。这可以通过单个查询来完成吗?

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    只使用两个同时查询可能会更高效,因为它的计算非常简单,而且赢家/输家字段很容易被索引。但是,我很好奇这是如何实现的。可以这样做:https://mongoplayground.net/p/JbBCzyln9o6

    db.collection.aggregate([
      // Combine the user _ids
      {$group: {
          _id: ["$_loserId", "$_winnerId"],
          // Track the amount of times user X lost to user Y
          times: {$sum: 1}
      }},
      
      // Seperate the user _ids
      // Track whether the user won by setting field 'lostWon': 0 if they lost 1 if they won
      {$unwind: {
          path: "$_id",
          includeArrayIndex: "lostWon"
      }},
    
      // Create a group for each user _id, user the 'lostWon' field to sum the totals
      {$group: {
        _id: "$_id",
        lost: {
          $sum: {
            $multiply: [
              "$times",
              {$cond: [{$eq: ["$lostWon", 0]}, 1, 0]}  // Important: swaps the values
            ]
          }
        },
        won: {
          $sum: {
            $multiply: [
              "$times",
              {$cond: [{$eq: ["$lostWon", 1]}, 1, 0]}  // This line is reduntant, but make query more understandable
            ]
          }
        },
      }},
    
      // Divide the ratio, if $lost is 0 use the won field value to avoid infinity
      {$addFields: {
        ratio: {
          $cond: [
            {$eq: ["$lost",0]},
            "$won",
            {$divide: ["$won", "$lost"]}
          ]
        }
      }}
    ])
    

    【讨论】:

    • 我添加了一个回调来获取结果,但是我得到的只是一个空数组。可能出了什么问题?
    • 可能有很多东西。如果可能的话,将您的查询发布到问题中,同时确保将collection 换成您想要的集合。我真的推荐使用Model.find({_winnerId: userId}).count()。这更像是一个概念证明,它会减慢你拥有的文件越多。
    • 是的,我正在使用 modelname.aggregate。现在,就是说,你的建议是我最初尝试的。但是我每次都返回 0,所以我想也许我走错了路。我正在这样做const numWins = await db.Game.find({ _winnerId: userId }).count(); 并得到 0。userId 是一个字符串。我试过使用 mongoose.Types.ObjectId(userId) 没有效果。
    • 您将需要 mongoose.Types.ObjectId。我应该把它包括在内。 Mongoose 会自动更改 _id 字段,但不会更改其他字段。你确定你连接到正确的数据库吗?
    • 如果您通过 mongoose 查询,只需使用模型 Game.find() 如果您通过 shell 查询,它可能位于 db.Games.find()db.games.find 下,具体取决于您的集合名称。
    猜你喜欢
    • 2022-01-24
    • 2017-06-19
    • 2018-03-18
    • 2021-11-19
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    相关资源
    最近更新 更多