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

求通用JavaScript对象合并结构化函数(按嵌套模板)

Hey, let's fix this nested object merging issue you're facing! I get that you need to group flat objects into a nested structure based on a predefined hierarchy, merging from bottom-up while preserving all non-key fields in a DATA layer—including fields that were used as keys in lower levels. Your current recursive approach is missing some grouping logic and handling levels incorrectly, which is why you're seeing missing data and duplicates at the CRT level. Let's break this down step by step.

Understanding the Core Requirements

First, let's restate your needs clearly to make sure we're on the same page:

  • Input: A flat array of objects (all with the same keys, varying values) + a nested "schema" object that defines the hierarchy of keys to group by.
  • Grouping Rule: Merge objects starting from the deepest key in the schema (bottom-up) to avoid losing unique values during merging.
  • Data Preservation: All non-key fields (and even fields that were used as keys in lower levels) should be stored in a DATA property at the deepest level of the nested structure.
What's Wrong with Your Current Code

Your existing function has a few critical issues:

  1. Top-Down Instead of Bottom-Up: You're traversing the schema from top to bottom, which means you're creating parent nodes before grouping by child keys—leading to duplicates and missing merged data.
  2. No Proper Grouping: You're passing single objects to the recursive call instead of grouping objects by the current key first. This prevents merging of objects with the same key value.
  3. Hardcoded Properties: HODNOTA, NAZEV, and META are hardcoded, which doesn't align with your requirement to use a generic DATA layer for all non-key data.
The Correct Implementation

Here's a robust solution that addresses all your requirements. It first extracts the bottom-up hierarchy from your schema, then recursively groups objects by each level:

function mergeNestedObjects(flatArray, structure) {
    // Extract the bottom-up hierarchy from the schema object
    const getKeyHierarchy = (obj, path = []) => {
        const entries = Object.entries(obj);
        if (entries.length === 0) return path;
        // Assume each level of the schema has exactly one key (as per your use case)
        const [key, nestedObj] = entries[0];
        // Prepend the current key to build bottom-up order
        return getKeyHierarchy(nestedObj, [key, ...path]);
    };
    const hierarchy = getKeyHierarchy(structure);

    // Recursive function to group objects by each level in the hierarchy
    const groupByLevel = (arr, remainingLevels) => {
        // No more levels to group by: collect all objects into DATA
        if (remainingLevels.length === 0) {
            return {
                DATA: arr.map(item => ({ ...item })) // Preserve all original fields, including former keys
            };
        }

        const currentKey = remainingLevels[0];
        const grouped = {};

        // Group objects by the current key's value
        arr.forEach(item => {
            const keyValue = item[currentKey];
            if (!grouped[keyValue]) {
                grouped[keyValue] = [];
            }
            grouped[keyValue].push(item);
        });

        // Recursively group each subset by the next level up
        Object.keys(grouped).forEach(key => {
            grouped[key] = groupByLevel(grouped[key], remainingLevels.slice(1));
        });

        return grouped;
    };

    return groupByLevel(flatArray, hierarchy);
}
How It Works

Let's walk through the logic with an example to make it concrete:

Example Input

// Flat object array
const flatData = [
    { CRT: 'CRT1', ZO: 'ZO1', SKUPINA: 'SK1', VALUE: 10 },
    { CRT: 'CRT1', ZO: 'ZO1', SKUPINA: 'SK2', VALUE: 20 },
    { CRT: 'CRT2', ZO: 'ZO1', SKUPINA: 'SK1', VALUE: 15 },
    { CRT: 'CRT2', ZO: 'ZO2', SKUPINA: 'SK1', VALUE: 30 }
];

// Schema defining the nested structure (bottom-up: SKUPINA → CRT → ZO)
const structure = {
    ZO: {
        CRT: {
            SKUPINA: null
        }
    }
};

Example Output

{
  "ZO1": {
    "CRT1": {
      "SK1": { "DATA": [ { "CRT": "CRT1", "ZO": "ZO1", "SKUPINA": "SK1", "VALUE": 10 } ] },
      "SK2": { "DATA": [ { "CRT": "CRT1", "ZO": "ZO1", "SKUPINA": "SK2", "VALUE": 20 } ] }
    },
    "CRT2": {
      "SK1": { "DATA": [ { "CRT": "CRT2", "ZO": "ZO1", "SKUPINA": "SK1", "VALUE": 15 } ] }
    }
  },
  "ZO2": {
    "CRT2": {
      "SK1": { "DATA": [ { "CRT": "CRT2", "ZO": "ZO2", "SKUPINA": "SK1", "VALUE": 30 } ] }
    }
  }
}

Key Details

  1. Bottom-Up Hierarchy Extraction: getKeyHierarchy parses your schema to get the order of keys from deepest to shallowest (e.g., ['SKUPINA', 'CRT', 'ZO'] for the example). This ensures we group by the most specific key first.
  2. Recursive Grouping: groupByLevel groups objects by the current key, then recursively processes each group with the next key in the hierarchy. This avoids duplicates and ensures all matching objects are merged under the correct nested path.
  3. Data Preservation: The DATA property at the deepest level contains full copies of all original objects, including fields that were used as keys in higher levels. This prevents any data loss.
Customization Tips
  • If you want to merge duplicate fields in DATA (e.g., combine VALUE into an array), you can modify the base case of groupByLevel to aggregate values instead of storing full objects.
  • If your schema has multiple keys at a level (unlikely per your description), you can adjust getKeyHierarchy to handle multiple keys per level.

内容的提问来源于stack exchange,提问作者Lukáš Schöbel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:45:29