🔨
JSON を CSV 用に変形するときは Array.prototype.flatMap() / flat() がいいよって小ネタ
どういうこと
色々なAPIをJSON形式で取得して、CSV形式に書き出したい、という需要はよくあります。
とはいえ、取得したデータの状態だとネストしていて、そのままではcsv-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