如何按嵌套属性meta.group对JavaScript对象数组进行分组
按嵌套属性
meta.group分组对象数组 问题背景
从API接口获取到Directus系统的字段配置对象数组,原始数据结构如下:
[ { "__typename": "directus_fields", "field": "heading", "type": "string", "schema": { "__typename": "directus_fields_schema", "max_length": 255, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "hero", "validation_message": null, "id": 37, "required": false, "validation": null, "interface": "input", "hidden": false } }, { "__typename": "directus_fields", "field": "introduction", "type": "text", "schema": { "__typename": "directus_fields_schema", "max_length": null, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "about_us", "validation_message": null, "id": 38, "required": false, "validation": null, "interface": "input-rich-text-html", "hidden": false } }, { "__typename": "directus_fields", "field": "campaign_title", "type": "string", "schema": { "__typename": "directus_fields_schema", "max_length": 255, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "campaign", "validation_message": null, "id": 41, "required": false, "validation": null, "interface": "input", "hidden": false } }, { "__typename": "directus_fields", "field": "campaign_duration", "type": "string", "schema": { "__typename": "directus_fields_schema", "max_length": 255, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "campaign", "validation_message": null, "id": 42, "required": false, "validation": null, "interface": "input", "hidden": false } }, { "__typename": "directus_fields", "field": "campaign_text", "type": "text", "schema": { "__typename": "directus_fields_schema", "max_length": null, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "campaign", "validation_message": null, "id": 43, "required": false, "validation": null, "interface": "input-rich-text-html", "hidden": false } }, { "__typename": "directus_fields", "field": "campaign_image", "type": "uuid", "schema": { "__typename": "directus_fields_schema", "max_length": 36, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "campaign", "validation_message": null, "id": 44, "required": false, "validation": null, "interface": "file-image", "hidden": false } }, { "__typename": "directus_fields", "field": "philosophy_title", "type": "string", "schema": { "__typename": "directus_fields_schema", "max_length": 255, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "philosophy", "validation_message": null, "id": 45, "required": false, "validation": null, "interface": "input", "hidden": false } }, { "__typename": "directus_fields", "field": "philosophy_text", "type": "text", "schema": { "__typename": "directus_fields_schema", "max_length": null, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "philosophy", "validation_message": null, "id": 46, "required": false, "validation": null, "interface": "input-rich-text-html", "hidden": false } }, { "__typename": "directus_fields", "field": "title", "type": "string", "schema": { "__typename": "directus_fields_schema", "max_length": 255, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "about_us", "validation_message": null, "id": 52, "required": false, "validation": null, "interface": "input", "hidden": false } }, { "__typename": "directus_fields", "field": "hero_text", "type": "text", "schema": { "__typename": "directus_fields_schema", "max_length": null, "is_unique": false, "is_nullable": true }, "meta": { "__typename": "directus_fields_meta", "group": "hero", "validation_message": null, "id": 164, "required": false, "validation": null, "interface": "input-rich-text-html", "hidden": false } } ]
需求为将数组内所有元素按照meta.group的取值分组,相同group值的元素归集到同一分组下。
原有实现为扁平数组转树形菜单的逻辑,无法满足分组需求,错误代码如下:
const tree = []; const children = {}; data.forEach((item) => { const newItem = { ...item } as ParsedMenuItem; const { id: newItem?.meta?.group, parentId: parentId = 0 } = newItem; children[id] = children[id] || []; newItem.childMenu = children[id]; parentId ? (children[parentId] = children[parentId] || []).push(newItem) : tree.push(newItem); }); return tree;
错误点说明
- 解构赋值语法错误:解构模式中不支持
newItem?.meta?.group这类可选链写法,无法正确读取嵌套的group属性 - 逻辑不匹配:原有代码是基于
id/parentId关联关系构建层级树,和当前按固定属性值聚合分组的需求完全不符 - 未处理嵌套属性取值:没有正确定位到分组依据的
meta.group字段作为聚合键
实现方案
使用reduce方法做聚合遍历,直接读取每个元素的meta.group值作为分组键即可,代码简洁且兼容性好:
function groupByMetaGroup(data) { return data.reduce((result, currentItem) => { const groupName = currentItem.meta.group; // 初始化对应分组的数组 result[groupName] ??= []; result[groupName].push(currentItem); return result; }, {}); } // 调用方法 const groupedData = groupByMetaGroup(apiResponseData);
注:如果需要兼容不支持空值合并运算符(
??=)的旧环境,可以将result[groupName] ??= []替换为result[groupName] = result[groupName] || [],效果完全一致。
如果业务场景需要数组格式的分组结果(用于前端列表渲染等场景),可以将对象结果转为数组结构:
const groupedList = Object.entries(groupedData).map(([groupKey, fieldList]) => ({ groupName: groupKey, fields: fieldList }));
输出结果
针对提供的测试数据,最终分组结果结构如下:
{ "hero": [heading字段对象, hero_text字段对象], "about_us": [introduction字段对象, title字段对象], "campaign": [campaign_title、campaign_duration、campaign_text、campaign_image四个字段对象], "philosophy": [philosophy_title、philosophy_text字段对象] }
内容的提问来源于stack exchange,提问作者Chinomso Johnson
相关产品推荐
相关产品推荐

