MongoDB(Python驱动)如何按文档内字段分组统计文档数量
Python操作MongoDB实现租车车辆聚合计数
场景说明
MongoDB实例中存储了数千条虚拟租车公司的车辆档案,单条文档结构如下:
{ "model": "Honda Civic", "license_plate": "ABC-1234", "attributes": { "rented": "YES", ...其他业务字段... } }
当前已实现逻辑为:先通过distinct("model")拉取所有车型,遍历每个车型单独构建聚合管道,匹配对应车型后投影出model、license_plate、attributes.rented字段逐行打印,运行结果符合预期,现有代码如下:
mydatabase = client.CARS_DB mycollection = mydatabase.RENTAL_LOT_A listOfRules = mycollection.distinct("model") for rule in listOfRules: match_variable = { "$match": { 'model': rule } } project_variable = { "$project": { '_id': 0, 'model': 1, 'license_plate': 1, 'attributes.rented': 1 } } pipeline = [ match_variable, project_variable ] results = mycollection.aggregate(pipeline) for r in results: print(r) print("- - - - - - - - - - - - - - - - -")
代码运行输出示例:
{'model': 'Honda Civic', 'license_plate': 'ABC-1234', 'attributes': {'rented': 'YES'}} - - - - - - - - - - - - - - - - - {'model': 'Toyota Camry', 'license_plate': 'ABC-5678', 'attributes': {'rented': 'YES'}} - - - - - - - - - - - - - - - - - {'model': 'Honda Civic', 'license_plate': 'DEF-1001', 'attributes': {'rented': 'no'}} - - - - - - - - - - - - - - - - -
待实现需求
现有逻辑仅能逐行返回单条车辆明细,无法满足统计需求,无需返回license_plate字段,需要实现两类统计效果:
- 仅按
model字段分组,统计每个车型对应的车辆总数量 - 按
model和attributes.rented字段联合分组,统计各车型下已出租、可租状态的车辆数量
此前尝试过Python端字典遍历统计、db.collection.countDocuments()等方案均未达到预期,可接受修改现有聚合管道或编写全新实现的方案。
实现方案
无需提前拉取全量车型再循环发起聚合请求,直接通过聚合管道的$group阶段在数据库侧完成统计即可,执行效率远高于循环请求的实现。
按车型统计总车辆数
将$group的分组键设置为$model,通过$sum累加器完成计数,参考代码:
pipeline = [ { "$group": { "_id": "$model", "total_count": {"$sum": 1} } }, # 可选阶段:调整输出字段结构,将分组键重命名为model,隐藏默认_id字段 { "$project": { "_id": 0, "model": "$_id", "total_count": 1 } } ] results = mycollection.aggregate(pipeline) for res in results: print(res)
返回结果示例:
{'total_count': 2, 'model': 'Honda Civic'} {'total_count': 1, 'model': 'Toyota Camry'}
按车型+出租状态联合统计
将$group的分组键设置为包含model和attributes.rented的复合键即可,参考代码:
pipeline = [ { "$group": { "_id": { "model": "$model", "rented_status": "$attributes.rented" }, "count": {"$sum": 1} } }, # 可选阶段:展平分组键结构,优化输出可读性 { "$project": { "_id": 0, "model": "$_id.model", "rented_status": "$_id.rented_status", "count": 1 } } ] results = mycollection.aggregate(pipeline) for res in results: print(res)
返回结果示例:
{'count': 1, 'model': 'Honda Civic', 'rented_status': 'YES'} {'count': 1, 'model': 'Toyota Camry', 'rented_status': 'YES'} {'count': 1, 'model': 'Honda Civic', 'rented_status': 'no'}
注意:当前示例数据中
attributes.rented字段值同时存在大写YES、小写no的格式差异,如果需要做状态归一化统计,可在$group阶段前增加$addFields阶段,通过$toLower操作符将状态值统一转为小写后再分组,避免同状态因大小写差异被拆分为多个分组。
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

