最直接做法是用 pandas.dataframe() 包裹 list(cursor),但需先将 objectid 转为字符串以防 typeerror;大数据量时应分批读取避免 oom,并用 json_normalize 处理嵌套字段缺失问题。

用 pandas.DataFrame() 包裹 list(cursor) 最直接
MongoDB 的 find() 返回的是游标(Cursor),不能直接传给 pandas.DataFrame()。最稳妥的做法是先转成 Python 列表,再构造 DataFrame:
import pandas as pd
from pymongo import MongoClient
<p>client = MongoClient('mongodb://localhost:27017/')
db = client['mydb']
collection = db['users']</p><h1>✅ 正确:显式转 list,再喂给 DataFrame</h1><p>df = pd.DataFrame(list(collection.find({'status': 'active'})))</p>不建议用 pd.DataFrame(collection.find(...)) —— 这会触发 Pandas 内部的不兼容解析逻辑,可能丢字段、错类型,尤其当文档含嵌套字典或 ObjectId 时。处理 ObjectId 字段导致的 TypeError
直接转 DataFrame 时,ObjectId 类型无法被 Pandas 序列化,报错:TypeError: Object of type ObjectId is not JSON serializable。必须提前转换:
from bson import ObjectId
<p>cursor = collection.find({'status': 'active'})
data = []
for doc in cursor:
doc['_id'] = str(doc['_id']) # 强制转字符串
data.append(doc)
df = pd.DataFrame(data)</p>
- 只对
_id做转换即可,其他字段一般无此问题 - 若需保留原始
ObjectId作后续查询,可额外加一列:doc['id_str'] = str(doc['_id']) - 不要用
json_util.dumps()全量序列化——它生成的是字符串,不是结构化数据
大数据量时避免内存爆掉
调用 list(cursor) 会一次性把所有结果加载进内存。查几十万条文档时,极易 OOM。
- 优先用
collection.find().limit(n)加限制,调试阶段别裸跑 - 真要全量导出,改用分批读取 +
pd.concat():def cursor_to_df_batched(collection, query={}, batch_size=10000): offset = 0 dfs = [] while True: batch = list(collection.find(query).skip(offset).limit(batch_size)) if not batch: break # 转 ObjectId for doc in batch: doc['_id'] = str(doc['_id']) dfs.append(pd.DataFrame(batch)) offset += batch_size return pd.concat(dfs, ignore_index=True) - 注意
skip()在大数据集上性能差,生产环境建议用_id范围分片(如{'_id': {'$gt': last_id}})
字段缺失导致列不齐?用 pd.json_normalize()
如果集合中文档结构不一致(比如有的有 address.city,有的没有),pd.DataFrame() 会自动补 NaN,但嵌套字段(如 address 字典)会被当做一个 object 列。想展开成扁平列,用:
from pandas import json_normalize
<p>data = list(collection.find({'status': 'active'}))
for doc in data:
doc['_id'] = str(doc['_id'])
df = json<em>normalize(data, sep='</em>')</p>
-
sep='_'把address.city变成address_city - 若某些文档缺整个
address字段,json_normalize仍能对齐列,比原生 DataFrame 更鲁棒 - 不支持多层重复数组展开(如
orders.items),这时得手写预处理
实际用的时候,ObjectId 转换和分批逻辑最容易漏,尤其本地调试时数据少看不出问题,一上生产就挂。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











