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

REST转GraphQL遇Float无法表示Infinity错误求解决方案

问题描述

将站点从REST迁移到GraphQL时,有一个接收period参数的查询:

valuations(period: $period) {
 low
}

Resolver中根据period调用MongoDB聚合查询,返回对应时间范围的结果:

valuations: async ({ collectible_id }, { period }, { prisma }) => {
    switch (true){
        case period === 1:
            return [await CollectiblePrice.aggregate([
                {
                    "$match": {
                        collectibleId: collectible_id,
                        "date": {
                            $gte: new Date(new Date().getTime() - (24 * 60 * 60 * 1000))
                        }
                    }
                },
            ])]
        case period === 2:
            return [await CollectiblePrice.aggregate([
                {
                    "$match": {
                        collectibleId: collectible_id,
                        "date": {
                            $gte: new Date(new Date().getTime() - (48 * 60 * 60 * 1000))
                        }
                    }
                },
            ])]
        case period === 7:
            console.log('7 day period...')
            return [await CollectiblePrice.aggregate([
                {
                    "$match": {
                        collectibleId: collectible_id,
                        "date": {
                            $gte: new Date(new Date().getTime() - (7 * 24 * 60 * 60 * 1000))
                        }
                    }
                },
            ])]
        case period === 28 || 30:
            return [await CollectiblePrice.aggregate([
                {
                    "$match": {
                        collectibleId: collectible_id,
                        "date": {
                            $gte: new Date(new Date().getTime() - (30 * 24 * 60 * 60 * 1000))
                        }
                    }
                },
            ])]
        case period === 90:
            return [await CollectiblePrice.aggregate([
                {
                    "$match": {
                        collectibleId: collectible_id,
                        "date": {
                            $gte: new Date(new Date().getTime() - (90 * 24 * 60 * 60 * 1000))
                        }
                    }
                },
            ])]
        default:
            return [await CollectiblePrice.aggregate([
            {
                "$match": {
                    collectibleId: collectible_id,
                    "date": {
                        $gte: new Date(new Date().getTime() - (24 * 60 * 60 * 1000))
                    }
                }
            },
        ])]
    }
}

多数period参数能正常运行,但传入90这类大值时,出现错误:

"message": "Float cannot represent non numeric value: Infinity",

该数据在REST API及图表包中均可正常使用,需解决如何允许或跳过异常值以正常返回结果。

解决方案

1. 在MongoDB聚合阶段过滤异常值

错误核心是返回的low字段存在Infinity值,而GraphQL的Float类型不支持该值。可以在聚合查询中直接过滤掉这类异常数据,在$match时间范围后新增一个过滤阶段:

// 以period=90的场景为例,其他case可同步修改
return [await CollectiblePrice.aggregate([
    {
        "$match": {
            collectibleId: collectible_id,
            "date": {
                $gte: new Date(new Date().getTime() - (90 * 24 * 60 * 60 * 1000))
            }
        }
    },
    {
        "$match": {
            "low": { $nin: [Infinity, -Infinity, NaN] } // 排除无限值和非数值
        }
    }
])]

2. 在Resolver中统一清洗返回结果

如果不想修改每个聚合查询,可在获取MongoDB返回结果后,遍历数据替换或移除异常值:

// 以任意case为例,替换原有返回逻辑
const rawResult = await CollectiblePrice.aggregate([/* 原查询逻辑 */]);
const cleanedResult = rawResult.map(item => ({
    ...item,
    low: isFinite(item.low) ? item.low : null // 将无限值转为null,也可根据业务替换为默认值(如0)
}));
return [cleanedResult];

3. 重构Resolver减少冗余(可选)

当前switch逻辑重复度极高,可重构为映射表简化代码,同时统一处理异常值:

valuations: async ({ collectible_id }, { period }, { prisma }) => {
    // 定义period对应天数的映射表
    const periodDaysMap = {
        1: 1,
        2: 2,
        7: 7,
        28: 30,
        30: 30,
        90: 90
    };
    // 默认返回1天的数据
    const targetDays = periodDaysMap[period] || 1;
    const timeRange = new Date(Date.now() - targetDays * 24 * 60 * 60 * 1000);

    const rawResult = await CollectiblePrice.aggregate([
        {
            "$match": {
                collectibleId: collectible_id,
                "date": { $gte: timeRange }
            }
        },
        {
            "$match": { "low": { $nin: [Infinity, -Infinity, NaN] } }
        }
    ]);

    // 最终清洗数据,确保符合GraphQL类型要求
    const cleanedResult = rawResult.map(item => ({
        ...item,
        low: isFinite(item.low) ? item.low : null
    }));

    return [cleanedResult];
}

4. 调整GraphQL Schema(可选)

如果业务允许low字段为空,可将Schema中的low类型改为可空:

type Valuation {
  low: Float # 原类型若为Float!,改为Float即可允许null值
}

这样当low为null时,GraphQL不会抛出类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:40:55