MongoDB聚合查询求助:统计冥想应用中最受欢迎的冥想内容
MongoDB聚合查询求助:统计冥想应用中最受欢迎的冥想内容
嘿,我懂你现在的烦恼——要从两个关联的集合里统计出最受欢迎的冥想内容,确实得把聚合管道的步骤捋清楚才行。你之前试过$unwind和$lookup没成功,大概率是因为字段类型不匹配或者管道顺序不对,我来给你拆解下正确的查询逻辑:
首先,核心思路是先把用户的每条收听记录拆出来,统计每个冥想ID的收听次数,再关联冥想的详细信息,最后排序。这里要注意一个关键细节:你的users集合里存的冥想ID是字符串格式,而meditations集合里的_id是ObjectId类型,直接关联会匹配不上,所以必须先做类型转换。
下面是完整的聚合查询代码:
db.users.aggregate([ // 1. 展开每个用户的收听记录数组,每条记录对应一次收听行为 { $unwind: "$userProgress.meditationsPracticed" }, // 2. 把字符串格式的冥想ID转换成ObjectId,方便后续关联meditations集合 { $addFields: { "meditationObjectId": { $toObjectId: "$userProgress.meditationsPracticed.id" } } }, // 3. 按冥想ID分组,统计每个冥想的总收听次数 { $group: { _id: "$meditationObjectId", listenCount: { $sum: 1 } } }, // 4. 关联meditations集合,获取冥想的详细信息(名称、时长等) { $lookup: { from: "meditations", localField: "_id", foreignField: "_id", as: "meditationInfo" } }, // 5. 展开关联后的冥想信息数组(因为$lookup返回的是数组) { $unwind: "$meditationInfo" }, // 6. 按收听次数降序排序,最受欢迎的排在最前面 { $sort: { listenCount: -1 } }, // 7. 可选:调整输出字段,只保留需要的内容 { $project: { _id: 0, listenCount: 1, meditationName: "$meditationInfo.name", meditationDuration: "$meditationInfo.duration" } } ])
我来给你解释下每一步的作用:
$unwind:把每个用户的meditationsPracticed数组拆成单独的文档,这样每条文档就代表一次独立的收听行为。$addFields:将字符串ID转为ObjectId,这步是关键!如果跳过,$lookup会因为类型不匹配查不到数据,这很可能是你之前失败的原因。$group:按转换后的冥想ID分组,用$sum:1统计每个ID出现的次数,也就是总收听量。$lookup:关联meditations集合,把对应冥想的详细信息拉取过来。$unwind:因为$lookup返回的是数组,展开后每条文档对应一个带详细信息的统计结果。$sort:按收听次数从高到低排序,直接得到最受欢迎的冥想列表。$project:可选步骤,用来整理输出格式,去掉不需要的字段,让结果更清晰。
如果你的users集合里的冥想ID已经是ObjectId类型(不是字符串),那可以去掉$addFields这一步,直接用$userProgress.meditationsPracticed.id来分组就行。
试试这个查询,应该就能得到你想要的结果啦!
备注:内容来源于stack exchange,提问作者Daniel Amram
相关产品推荐
相关产品推荐

