
本文详解如何通过 MongoDB 聚合框架($group + $push)和 PyMongo 驱动,将文档按 Model 分组,并为每个模型聚合其对应的 AP Name 列表,最终生成结构清晰的字典化结果。
本文详解如何通过 mongodb 聚合框架(`$group` + `$push`)和 pymongo 驱动,将文档按 `model` 分组,并为每个模型聚合其对应的 `ap name` 列表,最终生成结构清晰的字典化结果。
在 PyMongo 中实现“按某字段分组 → 收集另一字段值为列表”的需求,核心在于正确使用聚合管道中的 $group 阶段配合累加器(如 $push),而非仅用 $match 或 distinct() 手动循环处理——后者效率低、逻辑冗余,且易出错。
✅ 正确的聚合逻辑解析
你期望的输出本质是一个按 Model 分组、每个分组内聚合 AP Name 字段值为数组的结果。这需三步聚合操作:
-
$group:以"$Model"为_id分组键,并用"$push": "$AP Name"将同组所有设备名追加至Devices数组; -
$project:重命名_id为更语义化的"Model",隐藏_id字段("_id": 0),保留"Devices"; -
$sort:按Model升序排列,提升结果可读性。
对应 MongoDB Shell 查询如下:
db.collection.aggregate([
{ "$group": { "_id": "$Model", "Devices": { "$push": "$AP Name" } } },
{ "$project": { "_id": 0, "Model": "$_id", "Devices": 1 } },
{ "$sort": { "Model": 1 } }
])
✅ PyMongo 实现:封装可复用的聚合函数
以下 Python 函数支持动态指定分组字段(如 "Model")和待聚合字段(如 "AP Name"),返回标准字典迭代器:
def aggregate_grouped_list(collection, group_field, value_field, output_key="Devices"):
"""
对集合执行分组聚合:按 group_field 分组,将 value_field 的值收集为列表
:param collection: PyMongo Collection 对象
:param group_field: 用于分组的字段名(如 "Model")
:param value_field: 待聚合的字段名(如 "AP Name")
:param output_key: 输出数组的键名,默认为 "Devices"
:return: 生成器,每项为 {"Model": "...", "Devices": [...]}
"""
pipeline = [
{
"$group": {
"_id": f"${group_field}",
output_key: {"$push": f"${value_field}"}
}
},
{
"$project": {
"_id": 0,
group_field: "$_id",
output_key: 1
}
},
{"$sort": {group_field: 1}}
]
return collection.aggregate(pipeline)
# 使用示例
for doc in aggregate_grouped_list(coll_inv, "Model", "AP Name"):
print(doc)
输出示例:
{"Model": "Model-1", "Devices": ["Name-1", "Name-4"]}
{"Model": "Model-2", "Devices": ["Name-2", "Name-3"]}
⚠️ 注意事项:
- 字段名含空格(如
"AP Name")必须用双引号包裹,在聚合表达式中写作"$AP Name",PyMongo 会自动解析;- 不要尝试构造类似
{ "Model-1": { "Devices": [...] } }的嵌套字典结构——这需在应用层转换,聚合阶段应优先保证结构统一、易于序列化;- 若需进一步转为 Python 字典(键为 Model 名),可在聚合后用字典推导式处理:
result_dict = {item["Model"]: item["Devices"] for item in aggregate_grouped_list(...)}
✅ 进阶:支持多维度灵活分组
该函数具备良好扩展性。例如,若数据新增 "Colour" 字段,可一键切换分组维度:
# 按 Model 分组,统计各型号支持的颜色
for x in aggregate_grouped_list(coll_inv, "Model", "Colour", "Colours"):
print(x) # {'Model': 'Model-1', 'Colours': ['red', 'green']}
# 按 Colour 分组,统计各颜色覆盖的型号
for x in aggregate_grouped_list(coll_inv, "Colour", "Model", "Models"):
print(x) # {'Colour': 'green', 'Models': ['Model-1', 'Model-2']}
通过合理设计聚合管道与封装函数,即可高效、可维护地实现复杂分组统计需求,避免低效的客户端循环与多次查询。










