【问题标题】:Create csv out of array of objects with nested array of objects javascript使用嵌套的对象数组从对象数组中创建 csv
【发布时间】:2020-09-03 16:44:13
【问题描述】:

所以我正在尝试获取这两条数据

const headers = [
      { label: 'Item/Passage', key: 'objectType' },
      { label: 'Constraint Type', key: 'constraintType' },
      { label: 'Constraint Name', key: 'description' },
      { label: 'Lower', key: 'lowerBound' },
      { label: 'Upper', key: 'upperBound' },
      { label: 'Target Attribute', key: 'attributeName' },
      { label: 'Theta', key: 'referenceValue' },
      { label: 'Form/Passage', key: 'scope' },
      { label: 'Filter', key: 'filters' },
      { label: 'Filter values', key: 'filterValues' },
      { label: 'Min', key: 'min' },
      { label: 'Max', key: 'max' },
    ];
const array = [
  {
    "objectType": "Item",
    "constraintType": "Include",
    "description": "constraint1",
    "lowerBound": "1",
    "filters": [
      {
        "attributeName": "Item Identifier",
        "values": "I105_15201|I105_15202",
        "valueLowerBound": null,
        "valueUpperBound": null
      },
      {
        "attributeName": "Passage Item Order",
        "values": "5|1|3|4|6|7|8|9|10|11|12|13|14|15|16|None",
        "valueLowerBound": null,
        "valueUpperBound": null
      }
    ],
    "upperBound": "4",
    "attributeName": null,
    "referenceValue": "",
    "scope": null
  },
  {
    "objectType": "Passage",
    "constraintType": "Include",
    "description": "constraint2",
    "lowerBound": "1",
    "filters": [
      {
        "attributeName": "Passage Identifier",
        "values": "pid_1-1|pid_10-1|pid_2-1|pid_4-1|pid_5-1|pid_7-1|pid_8-1|pid_9-1",
        "valueLowerBound": null,
        "valueUpperBound": null
      },
      {
        "attributeName": "Word Count",
        "values": "",
        "valueLowerBound": 3,
        "valueUpperBound": 234
      }
    ],
    "upperBound": "4",
    "attributeName": null,
    "referenceValue": "",
    "scope": null
  },
  {
    "objectType": "Item",
    "constraintType": "Include",
    "description": "constraint3",
    "filters": [],
    "lowerBound": "1",
    "upperBound": "4",
    "attributeName": null,
    "referenceValue": "",
    "scope": null
  }
]

并生成一个如下所示的 csv 文件,

基本上,我从标头数组中获取标签值,创建标头,然后将每个约束放在自己的行上。如果约束具有过滤器,则会创建另一行并将值放置在最后四列中。例如,约束 1 和 2 有两个过滤器,约束 3 没有。

我已经能够使用以下代码完成,但感觉它不是一个非常稳定的实现。寻找有关如何实现这一点的任何建议。谢谢!

这是我能够创建的字符串的副本

toCsv -> csv Item/Passage,Constraint Type,Constraint Name,Lower,Upper,Target Attribute,Theta,Form/Passage,Filter,Filter values,Min,Max
Item,Include,constraint1,1,4,,,
,,,,,,,,Item Identifier,I105_15201|I105_15202,,
,,,,,,,,Passage Item Order,5|1|3|4|6|7|8|9|10|11|12|13|14|15|16|None,,
Passage,Include,constraint2,1,4,,,
,,,,,,,,Passage Identifier,pid_1-1|pid_10-1|pid_2-1|pid_4-1|pid_5-1|pid_7-1|pid_8-1|pid_9-1,,
,,,,,,,,Word Count,,3,234
Item,Include,constraint3,1,4,,,
export const toCsv = (array, headers) => {
  const getValuesFromObject = (obj) => {
    if (typeof obj !== 'object' || obj === null) {
      return [];
    }

    const headerKeys = Object.keys(headers);
    const keys = Object.keys(obj);
    const values = [];
    const filterValues = [];

    for (var i = 0; i < keys.length; ++i) {
      if (Array.isArray(obj[keys[i]])) {
        obj[keys[i]].map((filterObj) => {
          filterValues.push(',,,,,,,,' + Object.values(filterObj)); // this part bothers me the most. I use it to create empty cells for the filter rows.
        });
      } else {
        values.push(obj[keys[i]]);
      }
    }
    return [].concat([values]).concat(filterValues).join('\n');
  };

  const csvHeaders = headers.map((obj) => obj.label).join(',');
  const body = array.map(getValuesFromObject);
  let csv = [].concat([csvHeaders]).concat(body).join('\n');
  return csv;
};

【问题讨论】:

  • 你有上述数据想要的结果(文本形式)的例子吗?
  • @NinaScholz 我刚刚添加了我能够创建的 csv 字符串的副本。这有帮助吗?
  • 看起来,您有两种类型的行,并且您在标题中仅寻址一种/无类型。也许最好将项目与其过滤器分开。

标签: javascript arrays csv object nested


【解决方案1】:

您可以对对象、它们的过滤器进行单个循环并迭代键。

const
    toCsv = (array, headers) => {
        const getValuesFromObject = o => !o || typeof o !== 'object'
            ? []
            : [
                headers.map(({ key }) => key !== 'filters' && o[key] || '').join(),
                ...o.filters.map(q => headers.map(({ key }) => q[key] || '').join())
            ];

        return [
            headers.map((obj) => obj.label).join(','),
            ...array.flatMap(getValuesFromObject)
        ].join('\n');
    },
    headers = [{ label: 'Item/Passage', key: 'objectType' }, { label: 'Constraint Type', key: 'constraintType' }, { label: 'Constraint Name', key: 'description' }, { label: 'Lower', key: 'lowerBound' }, { label: 'Upper', key: 'upperBound' }, { label: 'Target Attribute', key: 'attributeName' }, { label: 'Theta', key: 'referenceValue' }, { label: 'Form/Passage', key: 'scope' }, { label: 'Filter', key: 'filters' }, { label: 'Filter values', key: 'values' }, { label: 'Min', key: 'valueLowerBound' }, { label: 'Max', key: 'valueUpperBound' }],
    array = [{ objectType: "Item", constraintType: "Include", description: "constraint1", lowerBound: "1", filters: [{ attributeName: "Item Identifier", values: "I105_15201|I105_15202", valueLowerBound: null, valueUpperBound: null }, { attributeName: "Passage Item Order", values: "5|1|3|4|6|7|8|9|10|11|12|13|14|15|16|None", valueLowerBound: null, valueUpperBound: null }], upperBound: "4", attributeName: null, referenceValue: "", scope: null }, { objectType: "Passage", constraintType: "Include", description: "constraint2", lowerBound: "1", filters: [{ attributeName: "Passage Identifier", values: "pid_1-1|pid_10-1|pid_2-1|pid_4-1|pid_5-1|pid_7-1|pid_8-1|pid_9-1", valueLowerBound: null, valueUpperBound: null }, { attributeName: "Word Count", values: "", valueLowerBound: 3, valueUpperBound: 234 }], upperBound: "4", attributeName: null, referenceValue: "", scope: null }, { objectType: "Item", constraintType: "Include", description: "constraint3", filters: [], lowerBound: "1", upperBound: "4", attributeName: null, referenceValue: "", scope: null }],
    result = toCsv(array, headers);
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 感谢 Nina,但上面仅在每个过滤器前显示五个逗号而不是七个逗号,以将过滤器名称移动到正确的过滤器列中。例如,,,,,项目标识符,,,,。输出需要是,,,,,,,,Item Identifier,I105_15201|... 我仍在研究你的逻辑,所以我还没有解决方案。只需注意我看到的输出。
  • attributeName 在索引 5 上,filters 在索引 8 上。这些值取自给定的标题键并插入到索引位置。如果你想在不同的索引有某个值,你需要在这个位置有一个对应的键。
猜你喜欢
  • 1970-01-01
  • 2019-10-06
  • 2021-11-28
  • 2021-08-02
  • 1970-01-01
  • 2020-12-21
  • 1970-01-01
  • 2019-04-23
  • 2015-10-18
相关资源
最近更新 更多