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

TypeScript如何将扁平化数据库查询结果转换为层级嵌套对象结构

问题描述

我有如下数据库查询结果,原始数据展示如下:
数据库查询结果

输入数据

const input = [
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_id: '44edfd7f-bc9e-4155-ad5c-5dace9c7c31a',
        ProductStock_id: '0a701dbc-2661-4d67-b764-632cfb67334f',
    },
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_id: '44edfd7f-bc9e-4155-ad5c-5dace9c7c31a',
        ProductStock_id: '15278807-794a-4727-9bcb-f7f68dfb4d41',
    },
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_id: '44edfd7f-bc9e-4155-ad5c-5dace9c7c31a',
        ProductStock_id: '0ac9fcd7-73f0-47b1-8fbc-3948863e7a89',
    },
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_id: '65e013a7-c7b2-47cf-88b7-2ab2d9bcd191',
        ProductStock_id: null,
    },
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_id: '8f00dde6-2548-46a7-a480-37e86a3ca895',
        ProductStock_id: '1439dde4-d184-4c98-b0c4-6d3c88ce8496',
    },
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_id: 'b48711b3-14b1-41ce-9f5f-4032297c1b8e',
        ProductStock_id: null,
    },
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_id: '4e22378d-cf56-4806-bea2-5ba0b220d3eb',
        ProductStock_id: null,
    },
];

预期输出格式

const output = [
    {
        PurchaseInvoice_id: '8e54a096-568b-48d9-8461-826be53a32da',
        PurchaseInvoicePosition_ids: [
            {
                PurchaseInvoicePosition_id: '44edfd7f-bc9e-4155-ad5c-5dace9c7c31a',
                ProductStock_ids: [
                    {
                        ProductStock_id: '0a701dbc-2661-4d67-b764-632cfb67334f',
                    },
                    {
                        ProductStock_id: '15278807-794a-4727-9bcb-f7f68dfb4d41',
                    },
                    {
                        ProductStock_id: '0ac9fcd7-73f0-47b1-8fbc-3948863e7a89',
                    },
                ],
            },
            {
                PurchaseInvoicePosition_id: '65e013a7-c7b2-47cf-88b7-2ab2d9bcd191',
                ProductStock_ids: [
                    {
                        ProductStock_id: null,
                    },
                ],
            },
            {
                PurchaseInvoicePosition_id: '8f00dde6-2548-46a7-a480-37e86a3ca895',
                ProductStock_ids: [
                    {
                        ProductStock_id: '1439dde4-d184-4c98-b0c4-6d3c88ce8496',
                    },
                ],
            },
            {
                PurchaseInvoicePosition_id: 'b48711b3-14b1-41ce-9f5f-4032297c1b8e',
                ProductStock_ids: [
                    {
                        ProductStock_id: null,
                    },
                ],
            },
            {
                PurchaseInvoicePosition_id: '4e22378d-cf56-4806-bea2-5ba0b220d3eb',
                ProductStock_ids: [
                    {
                        ProductStock_id: null,
                    },
                ],
            },
        ],
    },
];

折叠后的输出效果如下图所示:
输出结果

我日常主要做PHP开发,对JavaScript相关操作不熟悉,曾尝试多次遍历输入对象、在数组中搜索匹配UUID的方式实现,但都没有成功。另外输入数据中可能包含多个不同的PurchaseInvoice_id,每个PurchaseInvoice_id关联多个PurchaseInvoicePosition_id,每个PurchaseInvoicePosition_id又关联多个ProductStock_id,求正确的实现方法。

实现代码

该实现通过两层Map做缓存实现O(n)时间复杂度的分组,支持任意数量的不同发票ID、行项ID的场景:

function transformData(input) {
    const result = [];
    // 存储发票ID对应的发票对象
    const invoiceCache = new Map();
    // 存储 发票ID:行项ID 对应的行项对象,避免不同发票下相同行项ID冲突
    const positionCache = new Map();

    for (const item of input) {
        const invoiceId = item.PurchaseInvoice_id;
        const positionId = item.PurchaseInvoicePosition_id;

        // 处理发票层级分组
        if (!invoiceCache.has(invoiceId)) {
            const invoiceItem = {
                PurchaseInvoice_id: invoiceId,
                PurchaseInvoicePosition_ids: []
            };
            invoiceCache.set(invoiceId, invoiceItem);
            result.push(invoiceItem);
        }
        const currentInvoice = invoiceCache.get(invoiceId);

        // 处理行项层级分组
        const positionKey = `${invoiceId}:${positionId}`;
        if (!positionCache.has(positionKey)) {
            const positionItem = {
                PurchaseInvoicePosition_id: positionId,
                ProductStock_ids: []
            };
            positionCache.set(positionKey, positionItem);
            currentInvoice.PurchaseInvoicePosition_ids.push(positionItem);
        }
        const currentPosition = positionCache.get(positionKey);

        // 插入库存ID
        currentPosition.ProductStock_ids.push({
            ProductStock_id: item.ProductStock_id
        });
    }

    return result;
}

// 调用示例
const output = transformData(input);
console.log(output);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 00:36:05