嵌套对象递归过滤与属性设置问题求助
解决方案:嵌套对象按owner_id过滤并标记父级/匹配项
核心需求回顾
- 按
owner_id匹配对象,匹配项标记filtered: true - 匹配项的所有父级标记
parented: true并保留 - 递归处理最多4层嵌套结构,不能忽略被保留节点的任何子项(父级保留则子项必须保留,无论子项是否匹配)
- 可利用扁平化数组,这里直接通过递归实现
实现思路
- 收集相关节点ID:先递归遍历整个结构,找出所有匹配
owner_id的节点,同时收集这些节点的所有父级ID(确保父级被保留) - 构建过滤后结构:再次递归遍历原结构,根据收集到的ID标记节点属性,同时确保被保留节点的所有子项都被保留(不管子项是否匹配)
完整代码实现
function filterNestedCardsByOwner(cards, targetOwnerId) { // 第一步:收集所有需要保留的节点ID(匹配节点 + 所有父级节点) const relevantNodeIds = new Set(); function collectRelevantIds(nodes, currentPath = []) { for (const node of nodes) { const updatedPath = [...currentPath, node.id]; // 如果当前节点匹配owner_id,把路径上所有节点ID加入集合 if (node.owner_id === targetOwnerId) { updatedPath.forEach(id => relevantNodeIds.add(id)); } // 递归处理子节点 if (node.child_cards?.length) { collectRelevantIds(node.child_cards, updatedPath); } } } collectRelevantIds(cards); // 第二步:构建过滤后的结构,保留节点并标记属性 function buildFilteredStructure(nodes, isParentKept = false) { const result = []; for (const node of nodes) { const isNodeRelevant = relevantNodeIds.has(node.id); // 节点保留条件:自身是相关节点,或父节点被保留 const shouldKeepNode = isNodeRelevant || isParentKept; if (!shouldKeepNode) continue; // 创建节点副本,避免修改原数据 const processedNode = { ...node }; delete processedNode.child_cards; // 设置过滤标记 if (node.owner_id === targetOwnerId) { processedNode.filtered = true; } // 设置父级标记(自身不匹配但属于相关节点) else if (isNodeRelevant) { processedNode.parented = true; } // 递归处理子节点,传递父节点是否被保留的状态 if (node.child_cards?.length) { processedNode.child_cards = buildFilteredStructure(node.child_cards, shouldKeepNode); } result.push(processedNode); } return result; } return buildFilteredStructure(cards); }
测试示例
假设你的原始数据(补充id属性,需求说明所有对象包含id):
const objs = [ { id: 1, title: 'title.1', owner_id: 1, child_cards: [ { id: 11, title: 'title.1.1', owner_id: 2, child_cards: [ { id: 111, title: 'title.1.1.1', owner_id: 1 }, { id: 112, title: 'title.1.1.2', owner_id: 2 } ] }, { id: 12, title: 'title.1.2', owner_id: 2, child_cards: [ { id: 121, title: 'title.1.2.1', owner_id: 1 } ] }, ] }, { id: 2, title: 'title.2', owner_id: 3, child_cards: [ { id: 21, title: 'title.2.1', owner_id: 2 } ] }, { id: 3, title: 'title.3', owner_id: 1, child_cards: [ { id: 31, title: 'title.3.1', owner_id: 1 }, { id: 32, title: 'title.3.2', owner_id: 1 }, { id: 33, title: 'title.3.3', owner_id: 1 } ] } ];
调用函数过滤owner_id=2:
const filteredResult = filterNestedCardsByOwner(objs, 2); console.log(JSON.stringify(filteredResult, null, 2));
输出结果(符合需求,保留所有被保留节点的子项):
[ { "id": 1, "title": "title.1", "owner_id": 1, "parented": true, "child_cards": [ { "id": 11, "title": "title.1.1", "owner_id": 2, "filtered": true, "child_cards": [ { "id": 111, "title": "title.1.1.1", "owner_id": 1 }, { "id": 112, "title": "title.1.1.2", "owner_id": 2, "filtered": true } ] }, { "id": 12, "title": "title.1.2", "owner_id": 2, "filtered": true, "child_cards": [ { "id": 121, "title": "title.1.2.1", "owner_id": 1 } ] } ] }, { "id": 2, "title": "title.2", "owner_id": 3, "parented": true, "child_cards": [ { "id": 21, "title": "title.2.1", "owner_id": 2, "filtered": true } ] } ]
说明
- 代码会创建节点副本,不会修改原始数据
- 严格遵循需求:匹配节点标记
filtered:true,父级标记parented:true,被保留节点的所有子项都被保留(即使子项不匹配) - 自动处理最多4层嵌套结构,递归深度可适配实际层级
内容的提问来源于stack exchange,提问作者Yassine KAROUI
相关产品推荐
相关产品推荐

