如何通过MongoDB聚合框架统计未知技能的出现次数?
需求描述
给定MongoDB集合fighters中的文档如下:
[ { _id: "N0001", name: "Bruce Lee", skills: ["karate", "jiu jitsu"], }, { _id: "N0002", name: "Bruce Dee", skills: ["karate", "tae kwon do"], }, { _id: "N0003", name: "Bruce See", skills: ["aikido", "jiu jitsu"], }, { _id: "N0004", name: "Deuce Lee", skills: ["karate", "judo"], }, ]
需要统计每种技能的出现次数,得到如下结果:
{ karate: 3, jiu jitsu: 2, tae kwon do: 1, judo: 1, aikido: 1, }
当前通过Node.js脚本实现,但希望完全用MongoDB聚合框架完成,避免客户端多次查询,且技能列表未知,无法预先硬编码。
聚合框架实现方案
直接使用以下聚合管道即可完成需求:
db.fighters.aggregate([ // 拆分skills数组为单个技能文档 { $unwind: "$skills" }, // 按技能分组统计次数 { $group: { _id: "$skills", count: { $sum: 1 } } }, // 将统计结果整理为k-v格式的数组 { $group: { _id: null, skillsCount: { $push: { k: "$_id", v: "$count" } } } }, // 将数组转换为目标对象格式 { $replaceRoot: { newRoot: { $arrayToObject: "$skillsCount" } } } ])
步骤说明:
- $unwind:把每个文档的
skills数组拆分为多条独立文档,每条仅包含一个技能,为后续单技能统计做准备。 - 第一次$group:以技能名为分组键,用
$sum:1统计每个技能的出现次数。 - 第二次$group:将所有技能的统计结果聚合为一个包含
k(技能名)和v(次数)的数组。 - $replaceRoot + $arrayToObject:把数组格式的统计结果转换为目标对象,将数组中的k-v对映射为对象的键值对。
执行该聚合查询后,会直接返回符合要求的统计结果。
内容的提问来源于stack exchange,提问作者CodeoftheWarrior
相关产品推荐
相关产品推荐

