mongodb 中多个文档中数组中相等元素的计数

问题描述 投票:0回答:3

我正在开发一个简单的程序,通过n个玩家来计算特殊单位的总数。

我有与此类似的文档(简化版),其中数组 rosterUnits 的长度可以是 0 到 7。总共有 7 个特殊单位。我需要知道每个单位的球员名单中有多少人。

{
  {
    _id: ObjectId(...),
    member: {
      rosterUnits: [ "Unit1", "Unit2", "Unit3", "Unit4"]
    }
  },
  {
    _id: ObjectId(...),
    member: {
      rosterUnits: [ "Unit1", "Unit3"]
    }
  },
  ...
}

预期结果是这样的:

{
  _id: ...
  result: [
    {
      name: "Unit1"
      count: 2
    },
    {
      name: "Unit2"
      count: 1
    },
    {
      name: "Unit3"
      count: 2
    },
    ...
    {
      name: "Unit7"
      count: 0
    }
  ]
}

如何使用聚合管道实现此目的?

编辑(2/7/2023)

对不起大家,我以为我在这里提供了足够的细节,但是...... 文档非常大,并且在此阶段之前的管道非常长。 我想让你省去文件方面的麻烦

我的公会最多可容纳 50 名玩家。我搜索公会,然后 $unwind 公会成员并 $lookup 进入成员以获取 member.rosterUnit(s)。

这是我想出的完整查询:

db.getCollection('guilds').aggregate([
    { $match: { 'profile.id': 'jrl9Q-_CRDGdMyNjTQH1rQ' } },
    //{ $match: { 'profile.id': { $in : ['jrl9Q-_CRDGdMyNjTQH1rQ', 'Tv_j9nhRTgufvH7C7oUYAA']} } },
    { $project: { member: 1, profile: 1 } },
    { $unwind: "$member" },
    {
        $lookup: {
            from: "players",
            localField: "member.playerId",
            foreignField: "playerId",
            pipeline: [
                {
                    $project: {
                        profileStat: 1,
                        rosterUnit: {
                            $let: {
                                vars: { gls: ["JABBATHEHUTT:SEVEN_STAR", "JEDIMASTERKENOBI:SEVEN_STAR", "GRANDMASTERLUKE:SEVEN_STAR", "LORDVADER:SEVEN_STAR", "GLREY:SEVEN_STAR", "SITHPALPATINE:SEVEN_STAR", "SUPREMELEADERKYLOREN:SEVEN_STAR"], },
                                in: {
                                    $reduce: {
                                        input: "$rosterUnit",
                                        initialValue: [],
                                        in: {
                                            $cond: {
                                                if: { $gt: [{ $indexOfArray: ["$$gls", "$$this.definitionId"] }, -1] },
                                                then: { $concatArrays: ["$$value", [{ definitionId: "$$this.definitionId", count: 1 }]] },
                                                else: { $concatArrays: ["$$value", []] }
                                            }
                                        },
                                    }
                                }
                            }
                        }
                    }
                }
            ],
            as: "member"
        }
    },
    {
        $addFields: {
            member: { $arrayElemAt: ["$member", 0] },
            gpStats: {
                $let: {
                    vars: { member: { $arrayElemAt: ["$member", 0] } },
                    in: {
                        $reduce: {
                            input: "$$member.profileStat",
                            initialValue: {},
                            in: {
                                characterGp: {
                                    $arrayElemAt: [
                                        "$$member.profileStat.value",
                                        {
                                            $indexOfArray: [
                                                "$$member.profileStat.nameKey",
                                                "STAT_CHARACTER_GALACTIC_POWER_ACQUIRED_NAME"
                                            ]
                                        }
                                    ]
                                },
                                shipGp: {
                                    $arrayElemAt: [
                                        "$$member.profileStat.value",
                                        {
                                            $indexOfArray: [
                                                "$$member.profileStat.nameKey",
                                                "STAT_SHIP_GALACTIC_POWER_ACQUIRED_NAME"
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $group: {
            _id: "$profile.id",
            guildName: { $first: "$profile.name" },
            memberCount: { $first: "$profile.memberCount" },
            guildGp: { $first: "$profile.guildGalacticPower" },
            totalGp: { $sum: { $sum: [{ $toInt: "$gpStats.characterGp" }, { $toInt: "$gpStats.shipGp" }] } },
            avgTotalGp: { $avg: { $sum: [{ $toInt: "$gpStats.characterGp" }, { $toInt: "$gpStats.shipGp" }] } },
            characterGp: { $sum: { $toInt: "$gpStats.characterGp" } },
            shipGp: { $sum: { $toInt: "$gpStats.shipGp" } },

        }
    }

])

我想在组中添加新字段,并获得上面的所需结果。 如果我对member.rosterUnit执行$unwind,我如何返回成员分组?

(再次抱歉,这是我的第一个问题)

arrays mongodb aggregation-framework
3个回答
1
投票
  • 使用
    $unwind
    rosterUnits
    数组解构为单独的文档。
  • 然后使用
    $group
    rosterUnits
    值对文档进行分组,并计算每个单元的计数。
  • 然后使用
    $project
    将输出格式化为仅包含名称和计数字段。
db.collection.aggregate([
    { 
        $unwind: "$member.rosterUnits" 
    },
    { 
        $group: { 
            _id: "$member.rosterUnits", 
            count: { $sum: 1 } 
        } 
    },
    { 
        $project: { 
            _id: 0, 
            name: "$_id", 
            count: "$count" 
        } 
    }
])

0
投票

是的,我认为最好的方法是使用聚合。

我确信有更好的方法来做到这一点。 但这是解决方案,我希望它对你朋友有用。

基本上,我们将使用“$group”聚合,并在其中使用运算符“$cond”和“$in”,如果找到搜索的元素,我们将逐案验证。如果是这样,我们将添加 1,如果未找到该元素,则添加 0。

我推荐你下载mongodb compass来尝试一下

聚合:

    [{
     $group: {
      _id: null,
      Unit1: {
       $sum: {
        $cond: [
         {
          $in: [
           'Unit1',
           '$member.rosterUnits'
          ]
         },
         1,
         0
        ]
       }
      },
      Unit2: {
       $sum: {
        $cond: [
         {
          $in: [
           'Unit2',
           '$member.rosterUnits'
          ]
         },
         1,
         0
        ]
       }
      },
      Unit3: {
       $sum: {
        $cond: [
         {
          $in: [
           'Unit3',
           '$member.rosterUnits'
          ]
         },
         1,
         0
        ]
       }
      },
      Unit4: {
       $sum: {
        $cond: [
         {
          $in: [
           'Unit4',
           '$member.rosterUnits'
          ]
         },
         1,
         0
        ]
       }
      },
      Unit5: {
       $sum: {
        $cond: [
         {
          $in: [
           'Unit5',
           '$member.rosterUnits'
          ]
         },
         1,
         0
        ]
       }
      },
      Unit6: {
       $sum: {
        $cond: [
         {
          $in: [
           'Unit6',
           '$member.rosterUnits'
          ]
         },
         1,
         0
        ]
       }
      },
      Unit7: {
       $sum: {
        $cond: [
         {
          $in: [
           'Unit7',
           '$member.rosterUnits'
          ]
         },
         1,
         0
        ]
       }
      }
     }
    }, {
     $project: {
      _id: 0
     }
    }]

0
投票

查询

  • 因为你想统计可能不存在的值,你可以手动分组,并进行条件计数
  • 在分组之后,您可以进行额外的转换(如果您确实需要完全一样的预期输出)。对象到数组,并映射以给出字段名称(名称,计数)

Playmongo

aggregate(
[{"$unwind": "$member.rosterUnits"},
 {"$group": 
   {"_id": null,
    "Unit1": 
     {"$sum": 
       {"$cond": [{"$eq": ["$member.rosterUnits", "Unit1"]}, 1, 0]}},
    "Unit2": 
     {"$sum": 
       {"$cond": [{"$eq": ["$member.rosterUnits", "Unit2"]}, 1, 0]}},
    "Unit3": 
     {"$sum": 
       {"$cond": [{"$eq": ["$member.rosterUnits", "Unit3"]}, 1, 0]}},
    "Unit4": 
     {"$sum": 
       {"$cond": [{"$eq": ["$member.rosterUnits", "Unit4"]}, 1, 0]}},
    "Unit5": 
     {"$sum": 
       {"$cond": [{"$eq": ["$member.rosterUnits", "Unit5"]}, 1, 0]}},
    "Unit6": 
     {"$sum": 
       {"$cond": [{"$eq": ["$member.rosterUnits", "Unit6"]}, 1, 0]}},
    "Unit7": 
     {"$sum": 
       {"$cond": [{"$eq": ["$member.rosterUnits", "Unit7"]}, 1, 0]}}}},
 {"$unset": ["_id"]},
 {"$project": 
   {"result": 
     {"$map": 
       {"input": {"$objectToArray": "$$ROOT"},
        "in": {"name": "$$this.k", "count": "$$this.v"}}}}}])
© www.soinside.com 2019 - 2024. All rights reserved.