如何用Scala+ReactiveMongo单次查询分组统计MongoDB文件类型数量
解决MongoDB Scala聚合查询统计文件类型数量的问题
你的代码存在两个核心问题导致结果异常:
- Group阶段写法错误:原代码用
Group(BSONDocument("_id" -> "$contentType"))的方式不符合Scala驱动的API规范,无法正确生成分组的_id字段 - 只获取单个聚合结果:聚合查询会返回每个文件类型对应的统计文档,你只取了第一个结果,导致所有类型的数量都相同
修正后的代码
def contentTypeStats(implicit ec: ExecutionContext): Future[ContentTypesDTO] = { collectionFactory.collection().flatMap(collection => { import collection.AggregationFramework._ // 构建正确的聚合管道 val pipeline = List( Match(BSONDocument("metadata.s" -> BSONDocument("$ne" -> "thumbnail"))), Group(Field("contentType"))("count" -> Sum(1)) // 修正Group和Sum的写法 ) // 获取所有聚合结果,而非单个文档 val result: Future[List[BSONDocument]] = collection.aggregatorContext[BSONDocument](pipeline) .prepared.cursor.collect[List]() result.map { statsDocs => // 初始化各类型数量为0 var pngCount = 0L var jpgCount = 0L var pdfCount = 0L // 遍历所有统计文档,匹配类型赋值 statsDocs.foreach { doc => doc.getAsOpt[String]("_id").foreach { contentType => val count = doc.getAsOpt[Long]("count").getOrElse(0L) contentType match { case "image/png" => pngCount = count case "image/jpeg" => jpgCount = count case "application/pdf" => pdfCount = count case _ => // 忽略其他未知类型 } } } ContentTypesDTO(pngCount, jpgCount, pdfCount) } }) }
关键修正说明
- Group阶段:使用
Group(Field("contentType"))对应MongoDB聚合中的_id: "$contentType",这是Scala驱动中按字段分组的标准写法 - Sum操作:用
Sum(1)替代SumAll,对应MongoDB的$sum: 1,实现对每组文档的计数 - 结果收集:用
cursor.collect[List]()获取所有聚合结果文档,而不是只取第一个 - 结果映射:遍历所有统计文档,根据
_id(即contentType的值)来分别填充DTO的各个字段,确保每个类型的数量正确
内容的提问来源于stack exchange,提问作者ahabrahante
相关产品推荐
相关产品推荐

