You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何遍历MongoDB游标中的隔行文档并转换为DataFrame

解决MongoDB游标隔行取文档并转换为DataFrame的问题

嘿,我来帮你搞定这个MongoDB游标隔行取数转DataFrame的问题~先看看你之前两次尝试踩的坑:

为什么之前的尝试会报错?

  1. 尝试1的错误:MongoDB的Cursor对象只支持简单切片(比如cursor[:10]取前10条),但不支持带步长的切片(比如[::2]),所以直接用cursor[::2]会抛出IndexError。
  2. 尝试2的错误:range(0, cursor.count(), 2)生成的是整数序列,你把这些整数当成MongoDB文档来访问doc['data'],自然会报TypeError: 'int' object is not subscriptable。另外新版MongoDB里cursor.count()已被废弃,就算改用collection.count_documents(),也没法直接通过索引取游标里的文档——因为Cursor不是随机访问类型。

两种可行的解决方案

方案一:遍历游标时通过索引筛选(简单直接)

既然Cursor是可迭代对象,我们可以用enumerate给每个文档加上索引,然后只保留索引为偶数(或奇数)的文档,实现隔行取数:

all_df_forecast = []
# 用enumerate获取每个文档的索引和内容
for idx, doc in enumerate(cursor):
    # 这里取索引为偶数的文档(0、2、4...),如果要取奇数项就改成idx % 2 == 1
    if idx % 2 == 0:
        single_fc_df = pd.DataFrame(doc['data']['PRICES SPOT'])
        all_df_forecast.append(single_fc_df)

# 可选:把所有小DataFrame合并成一个大的
final_df = pd.concat(all_df_forecast, ignore_index=True)

这个方法不需要修改查询逻辑,直接在客户端处理筛选,适合数据量不大的场景。

方案二:用MongoDB聚合查询直接筛选(高效推荐)

如果你的MongoDB版本是4.4及以上,可以用聚合管道的$setWindowFields给每个文档添加行号,然后直接筛选隔行的文档,把筛选逻辑放到数据库端,减少客户端的数据传输量:

# 构建聚合管道
pipeline = [
    # 原始的匹配条件
    {
        "$match": {
            "Type": "f",
            "runTime": { "$gte": model_dt_from, "$lte": model_dt_till },
            "data.PRICES SPOT.0": { "$exists": True }
        }
    },
    # 给每个文档添加行号,按runTime排序(确保顺序稳定,可根据需求修改排序字段)
    {
        "$setWindowFields": {
            "sortBy": { "runTime": 1 },
            "output": {
                "rowNumber": { "$rowNumber": {} }
            }
        }
    },
    # 筛选行号为偶数的文档(rowNumber从1开始,所以%2==0对应第2、4...条)
    {
        "$match": {
            "rowNumber": { "$mod": [2, 0] }
        }
    },
    # 可选:移除不需要的rowNumber字段
    {
        "$unset": "rowNumber"
    }
]

# 执行聚合查询得到筛选后的游标
cursor = self._collection.aggregate(pipeline)

# 转换为DataFrame的逻辑和之前一致
all_df_forecast = []
for doc in cursor:
    single_fc_df = pd.DataFrame(doc['data']['PRICES SPOT'])
    all_df_forecast.append(single_fc_df)

final_df = pd.concat(all_df_forecast, ignore_index=True)

这个方法的优势是数据库直接返回你需要的隔行数据,不需要客户端处理大量冗余数据,适合数据量较大的场景。注意一定要指定稳定的排序字段(比如runTime),这样行号的顺序才符合你的预期。

内容的提问来源于stack exchange,提问作者nrvaller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:09:15