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

使用现代JavaScript查找深度嵌套对象中的指定产品

如何用现代JS方法从嵌套数据中查找目标PurchaseCardRecord对象

由于DatoCMS的GraphQL Schema不支持where过滤器,只能查询全部数据后在本地按ID查找目标对象。目标PurchaseCardRecord对象嵌套在foo.data.allGiveawayLandingPages→lpSection→products数组内,尝试多种ES6方法均未成功,仅旧版递归有效,现寻求更优雅的现代解法。

数据结构示例

"foo": {
  "data": {
    "allGiveawayLandingPages": [
      {
        "lpSection": [
          {},
          {},
          {},
          {},
          {},
          {},
          {},
          {
            "id": "34525949",
            "products": [
              {
                "__typename": "PurchaseCardRecord",
                "discountAmount": 50,
                "discountAmountPct": null,
                "discountEndDate": "2022-11-01T23:00:00+00:00",
                "id": "44144096"
              },
              {
                "__typename": "PurchaseCardRecord",
                "discountAmount": null,
                "discountAmountPct": null,
                "discountEndDate": null,
                "id": "44144097"
              }
            ]
          }
        ]
      }
    ]
  }
}

尝试过的失败方法

1. 嵌套find方法

const foo = await request({ query: ALL_PURCHASE_CARDS_QUERY });
const card = foo.data.allGiveawayLandingPages.find((page) => {
    return page.lpSection.find((section) => {
        return section?.products.find((record) => record.id === parentId)
    })
});
logger.debug({card}, 'Got card');

问题:find返回的是第一个满足条件的父级对象(allGiveawayLandingPages中的页面),而非目标PurchaseCardRecord本身;遇到空section时,section?.products会返回undefined,可能导致逻辑中断,且报错时错误对象为空无法调试。

2. reduce方法

const card = foo.data.allGiveawayLandingPages.reduce((accumulator, item) => {
    return item?.lpSection.reduce((section) => {
        return section?.products.reduce((record) => {
            if ('PurchaseCardRecord' === record.__typename && record.id === parentId) return record;
        })
    })
})

问题:reduce用法错误,未正确处理累加器参数,每一层reduce都没有返回有效的累加值,最终无法得到目标对象,反而可能返回父对象或undefined。

当前有效的旧版递归方法

function filterCards(object) {
    if (object.hasOwnProperty('__typename') && object.hasOwnProperty('id') && ('PurchaseCardRecord' === object.__typename && parentId === object.id)) return object;

    for (let i=0; i<Object.keys(object).length; i++) {
        if (typeof object[Object.keys(object)[i]] == 'object') {
            const o = filterCards(object[Object.keys(object)[i]]);
            if (o != null) return o;
        }
    }

    return null;
}

该方法能正常工作,但写法偏老旧,不够简洁。

优化后的现代JS解法

方法一:扁平化嵌套数组后直接查找

利用flatMap将嵌套数组展开为一维数组,再用find定位目标,逻辑清晰简洁:

const foo = await request({ query: ALL_PURCHASE_CARDS_QUERY });
const targetCard = foo.data.allGiveawayLandingPages
  .flatMap(page => page.lpSection)
  .flatMap(section => section?.products || [])
  .find(record => record?.__typename === 'PurchaseCardRecord' && record?.id === parentId);

说明:flatMap依次展开lpSection和products数组,section?.products || []处理空section避免报错,最后直接查找匹配ID和类型的对象。

方法二:现代递归写法

保留递归的灵活性,用现代JS语法简化代码:

const findTargetCard = (obj) => {
  if (obj?.__typename === 'PurchaseCardRecord' && obj?.id === parentId) return obj;
  for (const value of Object.values(obj)) {
    if (typeof value === 'object' && value !== null) {
      const result = findTargetCard(value);
      if (result) return result;
    }
  }
  return null;
};

const foo = await request({ query: ALL_PURCHASE_CARDS_QUERY });
const targetCard = findTargetCard(foo.data.allGiveawayLandingPages);

说明:用Object.values替代Object.keys遍历属性值,更直观;用可选链?.简化属性判断,代码更简洁易读。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 01:31:21