Pymongo使用aggregate分组无需累加器 查询按MMSI聚合的嵌套结构数据
问题排查与解决方法
报错原因
$match阶段语法错误:你写了两个同名MessageTime键,后写的"$lt": to_time会覆盖前一个"$gt": from_time,导致时间筛选逻辑失效,正确写法是把两个比较操作放在同一个MessageTime对应的对象里。$group阶段语法错误:MongoDB聚合的$group阶段不支持直接用字段值作为动态键名,你写的"$MMSI":{"accumulator1":"$ROT"}既不符合累加器语法规则,也没法实现动态键的效果,因此抛出字段需要累加器对象的报错。
实现方案
你要求的结构需要动态将MMSI字段值作为键,MongoDB原生聚合支持两种实现方式,均可以完全匹配你要求的返回结构:
方案1:聚合+Python轻量转换(推荐)
性能更好,兼容性更高,逻辑更易维护:
def track_route(from_time, to_time): doc = myCol.aggregate([ # 合并时间筛选条件 {"$match":{ "MessageTime":{"$gt": from_time, "$lt": to_time} }}, # 按MMSI分组,同组所有原文档存入data数组 {"$group":{ "_id": "$MMSI", "data": {"$push": "$$ROOT"} }} ]) # 转换为目标结构 doc_list = [{item["_id"]: item["data"]} for item in doc] return doc_list
方案2:纯聚合实现(MongoDB 3.4.4+支持)
不需要额外Python处理,直接通过聚合算子得到目标结构:
def track_route(from_time, to_time): doc = myCol.aggregate([ {"$match":{ "MessageTime":{"$gt": from_time, "$lt": to_time} }}, {"$group":{ "_id": "$MMSI", "data": {"$push": "$$ROOT"} }}, # 动态生成以MMSI为键的结构 {"$replaceRoot": { "newRoot": {"$arrayToObject": [[{"k": {"$toString": "$_id"}, "v": "$data"}]]} }} ]) doc_list = list(doc) return doc_list
如果你的MMSI本身是数字类型不需要转字符串,把{"$toString": "$_id"}改成"$_id"即可。
内容的提问来源于stack exchange,提问作者daemon03039
相关产品推荐
相关产品推荐

