首页 > 解决方案 > 从对象数组和javascript中的维度列表创建父子结构

问题描述

我按州、城市和产品从 mysql 表组中获取了销售数据。我使用以下查询从 MySql 表中获取数据

select state,city,product,sales from salesTable group by state,city,product;

并从查询中得到以下输出,

[
  {
    "state": "S1",
    "city": "CITY1",
    "product": "P1",
    "sales": 1000
  },
  {
    "state": "S1",
    "city": "CITY2",
    "product": "P1",
    "sales": 2000
  },
  {
    "state": "S1",
    "city": "CITY1",
    "product": "P2",
    "sales": 2000
  },
  {
    "state": "S2",
    "city": "CITY1",
    "product": "P1",
    "sales": 1000
  },
  {
    "state": "S2",
    "city": "CITY2",
    "product": "P1",
    "sales": 2000
  },
  {
    "state": "S2",
    "city": "CITY2",
    "product": "P2",
    "sales": 2000
  },
  {
    "state": "S3",
    "city": "CITY1",
    "product": "P2",
    "sales": 1000
  },
  {
    "state": "S3",
    "city": "CITY2",
    "product": "P2",
    "sales": 2000
  }
]

现在我想创建父子结构,dimensions=["state","city","product"] 其中州是祖父母,城市是父母(州的孩子),产品是孩子。

如果维度数组应该是动态的,它的长度可能会增加或减少。

我需要波纹管输出,

[
  {
    "sales": 5000,
    "state": "S1",
    "children": [
      {
        "sales": 3000,
        "state": "S1",
        "city": "CITY1",
        "children": [
          {
            "sales": 1000,
            "state": "S1",
            "city": "CITY1",
            "product": "P1"
          },
          {
            "sales": 2000,
            "state": "S1",
            "city": "CITY1",
            "product": "P2"
          }
        ]
      },
      {
        "sales": 2000,
        "state": "S1",
        "city": "CITY2",
        "children": [
          {
            "sales": 2000,
            "state": "S1",
            "city": "CITY2",
            "children": [
              {
                "sales": 2000,
                "state": "S1",
                "city": "CITY2",
                "product": "P1"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "sales": 5000,
    "state": "S2",
    "children": [
      {
        "sales": 1000,
        "state": "S2",
        "city": "CITY1",
        "children": [
          {
            "sales": 1000,
            "state": "S2",
            "city": "CITY1",
            "product": "P1"
          }
        ]
      },
      {
        "sales": 4000,
        "state": "S2",
        "city": "CITY2",
        "children": [
          {
            "sales": 4000,
            "state": "S2",
            "city": "CITY2",
            "children": [
              {
                "sales": 2000,
                "state": "S2",
                "city": "CITY2",
                "product": "P1"
              },
              {
                "sales": 2000,
                "state": "S2",
                "city": "CITY2",
                "product": "P2"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "sales": 3000,
    "state": "S3",
    "children": [
      {
        "sales": 1000,
        "state": "S3",
        "city": "CITY1",
        "children": [
          {
            "sales": 1000,
            "state": "S3",
            "city": "CITY1",
            "product": "P2"
          }
        ]
      },
      {
        "sales": 2000,
        "state": "S3",
        "city": "CITY2",
        "children": [
          {
            "sales": 2000,
            "state": "S3",
            "city": "CITY2",
            "children": [
              {
                "sales": 2000,
                "state": "S3",
                "city": "CITY2",
                "product": "P2"
              }
            ]
          }
        ]
      }
    ]
  }
]

标签: javascriptarraysgroup-bygroupingjavascript-objects

解决方案


也许是这样的。在第一次迭代中,我们使用时间对象而不是数组来构建树,以便于分发。在第二次递归迭代中,我们从时间对象创建数组并计算销售额。

为了统一,最顶层也使用.childrenkey及其.sales总和。这可以通过在末尾使用result.children而不是忽略。result

const data = [
  { state: 'S1', city: 'CITY1', product: 'P1', sales: 1000 },
  { state: 'S1', city: 'CITY2', product: 'P1', sales: 2000 },
  { state: 'S1', city: 'CITY1', product: 'P2', sales: 2000 },
  { state: 'S2', city: 'CITY1', product: 'P1', sales: 1000 },
  { state: 'S2', city: 'CITY2', product: 'P1', sales: 2000 },
  { state: 'S2', city: 'CITY2', product: 'P2', sales: 2000 },
  { state: 'S3', city: 'CITY1', product: 'P2', sales: 1000 },
  { state: 'S3', city: 'CITY2', product: 'P2', sales: 2000 },
];

const dimensions = ['state', 'city', 'product'];
const childKey = dimensions[dimensions.length - 1];

const result = { children: Object.create(null) };

for (const entry of data) {
  let parrent = null;
  let current = result.children;

  for (const dimension of dimensions) {
    let slot = current[entry[dimension]];
    if (!slot) {
      slot = current[entry[dimension]] = Object.create(null);
      slot.sales = dimension === childKey ? entry.sales : 0;

      if (parrent) {
        for (const [k, v] of Object.entries(parrent)) {
          if (k !== 'children' && k !== 'sales') slot[k] = v;
        }
      }

      slot[dimension] = entry[dimension];

      if (dimension !== childKey) {
        slot.children = Object.create(null);
      }
    }

    parrent = slot;
    current = slot.children;
  }
}

normalizeAndSum(result, null);

console.log(JSON.stringify(result, null, '  '));

function normalizeAndSum(object, parent) {
  if (object.children) {
    object.children = Object.values(object.children);
    for (const child of object.children) normalizeAndSum(child, object);
  }
  if (parent) {
    parent.sales = parent.children.reduce((acc, { sales }) => acc + sales, 0);
  }
}


推荐阅读