如何高效查询MongoDB中的集合成员关系?
用MongoDB聚合框架一次性统计关键词所有组合的共现次数
嘿,我懂你现在反复写8种查询有多麻烦——这活儿不仅枯燥,还容易写错,而且多次请求数据库也挺浪费资源的。其实用MongoDB的聚合框架就能一次性搞定所有组合的统计,只需要一次数据库请求,效率高多了!
核心思路
我们可以分三步完成:
- 给每篇文章标记是否包含目标关键词(A=scotland、B=church、C=queen);
- 根据这三个标记分组,统计每组的文章数量;
- 把分组结果转换成你需要的可读格式,最后按指定顺序整理成输出数组。
具体聚合查询代码
直接运行这个聚合命令,就能得到所有组合的统计结果:
db.article_list.aggregate([ // 第一步:标记每篇文章是否包含三个关键词 { $addFields: { hasA: { $in: ["scotland", "$keywords"] }, hasB: { $in: ["church", "$keywords"] }, hasC: { $in: ["queen", "$keywords"] } } }, // 第二步:按三个标记分组,统计每组的文档数 { $group: { _id: { hasA: "$hasA", hasB: "$hasB", hasC: "$hasC" }, count: { $sum: 1 } } }, // 第三步:将分组的布尔标记转换成易读的组合名称(可选,但更直观) { $project: { _id: 0, combination: { $switch: { branches: [ { case: { $and: ["$_id.hasA", "$_id.hasB", "$_id.hasC"] }, then: "A & B & C" }, { case: { $and: ["$_id.hasA", "$_id.hasB", { $not: "$_id.hasC" }] }, then: "A & B (无C)" }, { case: { $and: ["$_id.hasA", { $not: "$_id.hasB" }, "$_id.hasC"] }, then: "A & C (无B)" }, { case: { $and: ["$_id.hasA", { $not: "$_id.hasB" }, { $not: "$_id.hasC" }] }, then: "仅存在A" }, { case: { $and: [{ $not: "$_id.hasA" }, "$_id.hasB", "$_id.hasC"] }, then: "B & C (无A)" }, { case: { $and: [{ $not: "$_id.hasA" }, "$_id.hasB", { $not: "$_id.hasC" }] }, then: "仅存在B" }, { case: { $and: [{ $not: "$_id.hasA" }, { $not: "$_id.hasB" }, "$_id.hasC"] }, then: "仅存在C" }, { case: { $and: [{ $not: "$_id.hasA" }, { $not: "$_id.hasB" }, { $not: "$_id.hasC" }] }, then: "均不存在" } ] } }, count: 1 } } ])
聚合结果示例
这个查询会返回类似这样的结果(包含所有8种组合):
[ { "combination": "A & B & C", "count": 10 }, { "combination": "A & B (无C)", "count": 20 }, { "combination": "A & C (无B)", "count": 20 }, { "combination": "仅存在A", "count": 5 }, { "combination": "B & C (无A)", "count": 5 }, { "combination": "仅存在B", "count": 10 }, { "combination": "仅存在C", "count": 20 }, { "combination": "均不存在", "count": 10 } ]
转换成指定顺序的输出数组
如果需要把结果转换成你要求的逗号分隔数组格式,可以在客户端代码里做简单整理(以JavaScript为例):
// 定义你需要的输出顺序 const desiredOrder = [ "A & B & C", "A & B (无C)", "A & C (无B)", "仅存在A", "B & C (无A)", "仅存在B", "仅存在C", "均不存在" ]; // 假设聚合查询的结果存在results变量中 const resultMap = new Map(results.map(item => [item.combination, item.count])); const outputArray = desiredOrder.map(key => resultMap.get(key) || 0); // 输出最终结果 console.log(outputArray.join(', ')); // 输出: 10,20,20,5,5,10,20,10
为什么这个方案更好?
- 只需要一次数据库请求,减少了网络开销和数据库负载;
- 逻辑集中在聚合管道里,比写8个重复的count查询更易维护;
- 性能更优,尤其是当数据量很大时,聚合框架的处理效率远高于多次单独查询。
内容的提问来源于stack exchange,提问作者Laura Matilda
相关产品推荐
相关产品推荐

