🔨

JSON を CSV 用に変形するときは Array.prototype.flatMap() / flat() がいいよって小ネタ

に公開

どういうこと

色々なAPIをJSON形式で取得して、CSV形式に書き出したい、という需要はよくあります。

とはいえ、取得したデータの状態だとネストしていて、そのままではcsv-stringifyするには不適切なことがあります。

https://csv.js.org/stringify/

つまり、深さ1のkey-valueのJSONにしたいです。で flatMap() だとそういう処理が楽に書けるよってことです。

コード

Deno で書いていますが、適宜Importは読み替えしてください。

Order には複数の Item が紐づいています。これをCSV用に、 Item 1つにつき1行のデータにしたい、とします。

import { stringify } from "npm:csv-stringify/sync";

const data = [
  {
    orderId: "123",
    customerId: "456",
    items: [
      { productId: "789", sku: "ABC", quantity: 2, price: 19.99 },
      { productId: "012", sku: "DEF", quantity: 1, price: 29.99 },
    ],
  },
  {
    orderId: "124",
    customerId: "457",
    items: [{ productId: "012", sku: "DEF", quantity: 1, price: 29.99 }],
  },
];

// item 1個で、1行のデータにしたい
const data2 = data.flatMap((order) =>
  order.items.map((item) => ({
    orderId: order.orderId,
    customerId: order.customerId,
    ...item,
  }))
);

// または map で書いて、最後に flat() するでもOK
const data2 = data
  .map((order) =>
    order.items.map((item) => ({
      orderId: order.orderId,
      customerId: order.customerId,
      ...item,
    }))
  )
  .flat();

console.log(data);
console.log(data2);

// CSV に変換
const output = stringify(data2, {
  header: true,
});
console.log(output);

出力例

// こんな形式の子要素に配列があるJSONを
[
  {
    orderId: "123",
    customerId: "456",
    items: [
      { productId: "789", sku: "ABC", quantity: 2, price: 19.99 },
      { productId: "012", sku: "DEF", quantity: 1, price: 29.99 }
    ]
  },
  {
    orderId: "124",
    customerId: "457",
    items: [ { productId: "012", sku: "DEF", quantity: 1, price: 29.99 } ]
  }
]

// こんな形式の平坦化したJSONにできる
[
  {
    orderId: "123",
    customerId: "456",
    productId: "789",
    sku: "ABC",
    quantity: 2,
    price: 19.99
  },
  {
    orderId: "123",
    customerId: "456",
    productId: "012",
    sku: "DEF",
    quantity: 1,
    price: 29.99
  },
  {
    orderId: "124",
    customerId: "457",
    productId: "012",
    sku: "DEF",
    quantity: 1,
    price: 29.99
  }
]

// 深さ1のJSONを CSV に変換
orderId,customerId,productId,sku,quantity,price
123,456,789,ABC,2,19.99
123,456,012,DEF,1,29.99
124,457,012,DEF,1,29.99

まとめ

デカいJSONをコネコネしているとこういう作業があり、手癖で書いて「なんかできた」になりがちなので、備忘録として残しました。

Discussion