ネスト JSON を CSV に平坦化する方法:5 つの戦略と選択マトリクス
幾何学的な問題
毎回同じ壁にぶつかる。API はネストした JSON を返してくるのに、Slack のアナリストはただスプレッドシートが欲しいだけ。mongoexport は $oid ラッパーと 3 階層のメタデータを吐き出し、BigQuery はフラットなテーブルを要求してくる。ネスト JSON を CSV に平坦化するのは構文の問題ではない。幾何学的な問題だ。JSON は木構造、CSV はグリッド。枝をどう畳むかを決めずに、木をグリッドへ移すことはできない。
畳み方の戦略は、ちょうど 5 つある。誤ったものを選べば、200 列の Excel を渡してしまったり、Twitter ID の精度を失ったり、パイプラインが依存する往復変換を壊したりする。正しいものを選べば、変換はワンライナーで済む。
| 戦略 | ワンライナー | 適した用途 |
|---|---|---|
| ドット記法 | customer.address.city | Excel/Sheets の分析 |
| アンダースコア | customer_address_city | SQL に親和的な列名 |
| インデックス配列 | items.0.sku, items.1.sku | 固定長配列 |
| 行展開 | 子要素ごとに親を反復 | Pandas/BigQuery 分析 |
| Stringify | 単一セルに "{\"city\":\"Seattle\"}" | 可逆な往復変換 |
以下では 5 戦略を順に見て、コンシューマ別(Excel、Pandas、BigQuery、Postgres)の選択マトリクスを示し、最適戦略が一見では分かりにくい実ペイロードを 4 件取り上げる。双方向変換の総合的な概要(パーサーライブラリ、ストリーミング、エンコーディングの罠)については、CSV ↔ JSON 変換ガイドを参照してほしい。
なぜネスト JSON は CSV に収まらないのか
JSON は CSV に存在しない 3 種類の構造を運ぶ。階層はオブジェクトの中のオブジェクト。シーケンスは配列。混在はその組み合わせ:オブジェクトの配列、配列を持つオブジェクト、配列の配列。典型的な EC サイトの注文は、その 3 つすべてを同時に含む。
CSV はちょうど 2 次元しか持たない:行と列。「この列が 3 つの子を保持する」ための第 3 の軸は存在しない。木からグリッドを要求するなら、何かを犠牲にしなければならない。子要素を複数の列に広げる(items.0.options.0.value のような名前と共存する)、複数の行に広げる(親フィールドが反復する)、あるいはテキストとして 1 セルに押し込み、もはや構造として扱わない。
以下の各戦略は、それぞれ異なる答えを返す。可読性を保ち往復安全性を失うものもあれば、その逆もある。万能なものはない。次にファイルを読む相手に合わせて答えを選ぶ。
5 つの平坦化戦略の比較
戦略 1:ドット記法(customer.address.city)
ドット記法はルートからリーフへ辿り、. でキーを連結する。ネストしたオブジェクトはリーフごとに 1 列となり、パスが列名にエンコードされる。
{ "customer": { "address": { "city": "Seattle" } }, "email": "alice@example.com" }
は以下のようになる。
customer.address.city,email
Seattle,alice@example.com
Pandas なら 1 行で完結する:
import pandas as pd
data = [{"customer": {"address": {"city": "Seattle"}}, "email": "alice@example.com"}]
df = pd.json_normalize(data, sep='.')
df.to_csv("out.csv", index=False)
JavaScript なら、小さな再帰関数で十分だ:
function flattenDot(obj, prefix = '', acc = {}) {
for (const [k, v] of Object.entries(obj)) {
const key = prefix ? `${prefix}.${k}` : k;
if (v && typeof v === 'object' && !Array.isArray(v)) {
flattenDot(v, key, acc);
} else {
acc[key] = v;
}
}
return acc;
}
**長所:**人間が読みやすい、Pandas のデフォルト、元のパスを保持。**短所:**列名が長くなりがち(Kubernetes のスペックは spec.template.spec.containers.0.resources.limits.memory のような名前を生む)、実際のキーに . が含まれる場合(Google Analytics 4 のイベントパラメータがそうだ)にドットが曖昧になる。
戦略 2:アンダースコア記法(customer_address_city)
考え方は同じで、区切り文字が違うだけ。. を _ に置き換えれば、結果は SQL セーフになる:SELECT customer_address_city FROM events は識別子を引用符で囲まずに動く。BigQuery、Snowflake、Postgres はいずれもこちらを好む。
import pandas as pd
df = pd.json_normalize(data, sep='_')
ドットとアンダースコアの選択は、純粋に下流のツール次第だ。Excel のアナリストはドットを自然に読む;SQL エンジンは文句を言わずアンダースコアを受け入れる。引数を 1 つ変えれば切り替わる。
**長所:**SQL セーフな列名、BigQuery 準拠の識別子、引用符不要。**短所:**キーに _ が含まれる場合(. よりは少ないが、なくはない)には曖昧さが残る。
戦略 3:インデックス配列(items.0.sku, items.1.sku)
オブジェクトはキーが一意なので、きれいに平坦化できる。配列は長さに上限がないので、そうはいかない。インデックス戦略は配列位置をパスのセグメントとして扱う:items[0] は items.0 になる。
{ "id": "ord-001", "items": [{"sku": "A"}, {"sku": "B"}] }
は以下のようになる。
id,items.0.sku,items.1.sku
ord-001,A,B
これが JSON to CSV コンバータ の Flatten のデフォルト挙動だ。各リーフが独自の列を持ち、位置は名前に記録される。
**長所:**すべての値が独自のセルを持つ、位置が保たれる、行の重複がない。**短所:**列数が爆発する(100 アイテム= 100 列)、配列長が異なる行は不揃いなテーブルを生む、下流の集計が壊れる(SUM(items.*.qty) ができない)。
戦略 4:行展開(配列を複数行へ)
配列に合わせてテーブルを横に広げるのではなく、縦に伸ばす。配列要素 1 つにつき親フィールドを 1 回ずつ反復し、各要素を独自の行にする。
{ "order_id": "ord-001", "customer": "Alice", "items": [{"sku": "A", "qty": 2}, {"sku": "B", "qty": 1}] }
は以下のようになる。
order_id,customer,items.sku,items.qty
ord-001,Alice,A,2
ord-001,Alice,B,1
Pandas なら 1 行で展開と正規化の両方ができる:
import pandas as pd
orders = [{"order_id": "ord-001", "customer": "Alice",
"items": [{"sku": "A", "qty": 2}, {"sku": "B", "qty": 1}]}]
df = pd.json_normalize(orders, record_path='items', meta=['order_id', 'customer'])
df.to_csv("orders.csv", index=False)
SQL なら、UNNEST が同じ役割を果たす:
SELECT order_id, item.sku, item.qty FROM orders, UNNEST(items) AS item;
**長所:**Pandas と BigQuery がこの形をネイティブに扱う、集計が機能する(GROUP BY order_id)、スキーマがスリムに保たれる。**短所:**親フィールドがすべての子行に重複する(ストレージが膨張する)、1 対多の境界が暗黙的(order_id が必要)、同レベルに 2 つの配列があると、慎重に UNNEST しない限りデカルト積になる。
戦略 5:Stringify(セル内 JSON)
過激な選択肢:そもそも平坦化しない。ネストした値全体を JSON 文字列としてシリアライズし、単一セルに入れる。外側のテーブルはフラットなまま、構造は内部に逐語的に保たれる。
{ "id": "ord-001", "items": [{"sku": "A"}, {"sku": "B"}] }
は以下のようになる。
id,items
ord-001,"[{""sku"":""A""},{""sku"":""B""}]"
これが JSON to CSV コンバータ の Stringify モードだ。列数が爆発することはなく、元の形がバイト単位で保たれ、逆変換は入力を厳密に再構築する。
**長所:**100% 可逆、列数が予測可能、逆変換時の Infer types と組み合わせれば往復安全。**短所:**Excel ユーザにはエスケープされた引用符が見える、SQL エンジンは値を問い合わせるのに JSON 関数が必要(BigQuery では JSON_EXTRACT_SCALAR、Postgres では ->>'key')、スプレッドシートの関数式はセル内部に手が届かない。
5 戦略の横並び比較
同じ入力を 5 戦略すべてで処理:{"id":"ord-001","customer":{"name":"Alice"},"items":[{"sku":"A","qty":2},{"sku":"B","qty":1}]}。
| 戦略 | 列数 | 往復安全 | 最適なコンシューマ |
|---|---|---|---|
| ドット記法 | 配列に伴い増加 | 不可 | Excel のアナリスト |
| アンダースコア | 配列に伴い増加 | 不可 | SQL ウェアハウス |
| インデックス配列 | 配列スロットごとに 2 列 | 不可(逆変換で曖昧) | 固定長配列 |
| 行展開 | スリム、子ごとに 1 行 | 部分的(キーが必要) | Pandas/BigQuery |
| Stringify | 固定 | 可 | パイプラインの往復 |
選択マトリクス:コンシューマ別の推奨戦略
まずコンシューマを引き、対応する推奨戦略を読み取る。
| コンシューマ | 推奨戦略 | 理由 |
|---|---|---|
| Excel/Sheets(アナリスト) | ドット + 大きい配列は Stringify | 読みやすい列名;大きな配列でもシートが爆発しない |
| Excel-EU(DE/FR/IT/ES) | ドット + ; 区切り + UTF-8 BOM | セミコロン必須;BOM で文字化け防止 |
Pandas(json_normalize + explode) | アンダースコア + 行展開 | SQL 親和的な列;展開は groupby と相性が良い |
| BigQuery/Snowflake | TSV + Stringify か行展開 | タブは引用符の罠を回避;JSON_EXTRACT でセル内を問い合わせ |
PostgreSQL COPY | RFC 4180 + アンダースコア + フラット | SQL セーフな列;厳格な RFC 引用 |
| MongoDB → BigQuery ETL | NDJSON を直接ロード、CSV はスキップ | BigQuery は NDJSON をネイティブにロード;CSV は遠回り |
Excel/Google Sheets:ロケールの罠
Excel の列名に実用的な長さ制限はない。本当の罠は 3 つある。
第 1 に、ロケールの分断。ヨーロッパの Excel(ドイツ、フランス、イタリア、スペイン)は , が小数点なので、区切り文字に ; を期待する。カンマ区切りの CSV を開くと、すべての行が A 列に潰れて入る。json-to-csv ツールの Excel プリセットは、ワンクリックで ; + CRLF + UTF-8 BOM へ切り替わる。
第 2 に、指数表記。Excel は 9007199254740993 を 9.00719925474E+15 として表示する。大きな整数は元の JSON で文字列として保持し、BOM を有効化して Excel にセルをテキスト扱いさせる。コンバータ側で大きな整数は自動検出している。
第 3 に、実用的な列数の限界。Excel は理論上 16,384 列をサポートするが、500 列を超えると扱いきれなくなる。重いサブツリーを Stringify するか、変換前に jq で射影しておく。
Pandas:json_normalize + explode
ネストした配列に対する標準パターンは、record_path + meta を 1 パスで使うことだ:
import pandas as pd
orders = [{
"order_id": "ord-001",
"customer": {"name": "Alice", "city": "Seattle"},
"items": [{"sku": "SKU-100", "qty": 2}, {"sku": "SKU-205", "qty": 1}]
}]
df = pd.json_normalize(orders, record_path='items',
meta=['order_id', ['customer', 'name'], ['customer', 'city']], sep='_')
df.to_csv("orders.csv", index=False)
出力はアイテムごとに 1 行で、order_id、customer_name、customer_city が反復される。これは先に explode を実行してから json_normalize するより優れる:record_path は中間のオブジェクト列をスキップし、meta でどの親フィールドを伝播させるか制御できる。配列要素がさらにネストしたオブジェクトを含む入力では、max_level= で深さに上限を設ける。
BigQuery/Snowflake:TSV + セル内 JSON
BigQuery の LOAD DATA は CSV の引用に厳格で、引用テキスト内にカンマがあるファイルをしばしば誤解釈する。テキストフィールド内にタブがほぼ現れないため、TSV のほうが安全だ:
bq load --source_format=CSV --field_delimiter='\t' \
dataset.orders gs://bucket/orders.tsv \
order_id:STRING,customer:STRING,items:STRING
ネストデータを単一列の Stringified JSON としてロードしても、BigQuery は JSON_EXTRACT_SCALAR でその中を問い合わせられる:
SELECT order_id, JSON_EXTRACT_SCALAR(items, '$[0].sku') AS first_sku
FROM dataset.orders;
Snowflake は VARIANT で同等の機能を提供し、items:0.sku::STRING のようなパスクエリを書ける。両方のエンジンで、ネストした配列が大きいか可変長の場合、完全な平坦化よりも Stringify + JSON パスクエリのほうが優れる。
PostgreSQL COPY:RFC 4180 厳格
COPY ... FROM ... WITH (FORMAT csv, HEADER true) は、現場で出会う中で最も厳格な RFC 4180 リーダーだ。2 つの挙動が人を躓かせる。
第 1 に、COPY は UTF-8 BOM を受け付けない。バイト順マークが最初の列名のリテラル接頭辞になり(id ではなく id)、id を参照するクエリはすべて静かに失敗する。Postgres を対象とする場合は BOM を切る。
第 2 に、COPY はネストデータをネイティブにはパースできない。ロード前に配列を複数行へ展開するか、宛先を jsonb として定義し、ネストした値を Stringify する:
CREATE TABLE orders (order_id text PRIMARY KEY, customer text, items jsonb);
COPY orders FROM '/tmp/orders.csv' WITH (FORMAT csv, HEADER true);
SELECT order_id, items->0->>'sku' AS first_sku FROM orders;
エンドツーエンドで JSON を喋るパイプラインなら、CSV をスキップして、代わりに JSON 行入力で COPY ... FROM ... WITH (FORMAT text) を使う。
実世界のペイロード解説
解説 1:EC サイトの注文(顧客 + items 配列)
典型的な注文は、ネストした顧客情報と可変長の items 配列を組み合わせる:
[{ "id": "ord-001",
"customer": { "name": "Alice", "address": {"city": "Seattle", "country": "US"} },
"items": [{"sku": "SKU-100", "qty": 2}, {"sku": "SKU-205", "qty": 1}] }]
正しい戦略は、ファイルを読む相手次第だ。財務部門は SKU ごとの売上を計算したいので、1 アイテム 1 行が欲しい。それが行展開戦略で、id と customer.name を反復する 2 行を生む。オペレーション部門はフルフィルメントのダッシュボード用に 1 注文 1 行が欲しい。それがドット記法 + items を Stringify するパターンで、配列が列数を爆発させない。同じ入力で 2 つの出力、どちらもそれぞれのコンシューマには正しい。
手元で試したいなら、ペイロードを JSON to CSV コンバータに貼り付け、Nested オプションで Flatten と Stringify を切り替えてみる。「Nested E-commerce Orders」の例が同じ形をロードする。
解説 2:GitHub Issues API(labels 配列 + user オブジェクト)
/repos/{owner}/{repo}/issues エンドポイントは、混在したネスト構造を返す:
[{ "id": 1001, "title": "Bug: login 404", "state": "open",
"labels": ["bug", "priority:high"], "user": {"login": "alice"} }]
user は有用なフィールドが 1 つだけのオブジェクト;labels は長さに上限のない文字列配列。実用的な平坦化はハイブリッドだ:user にはドット記法(user.login だけが必要)、labels には ; で区切って単一セルへインラインで結合する:
id,title,state,labels,user.login
1001,Bug: login 404,open,bug;priority:high,alice
「配列をセルに結合する」と「オブジェクトをドットで平坦化する」の両方を、1 つの戦略では捉えられない。オブジェクトの平坦化はコンバータが自動で処理するので、labels の側を jq(map(.labels = (.labels | join(";"))))で前処理するか、デフォルトの配列 Stringify 挙動を受け入れることになる。
解説 3:MongoDB の mongoexport($oid + メタデータ)
mongoexport --jsonArray は Extended JSON のラッパーを吐き出す:
[{ "_id": {"$oid": "6634a1b2c3d4e5f600000001"},
"email": "alice@example.com",
"metadata": { "signupDate": "2026-01-15T10:30:00Z",
"preferences": {"newsletter": true, "theme": "dark"} } }]
$oid ラッパーは、文字通り _id.$oid という名前の列を生み、ほとんどの SQL エンジンは拒否する。jq で前処理してアンラップする:
mongoexport --collection=users --jsonArray | jq 'map(._id = ._id."$oid")' > users.json
深くネストした metadata.preferences ブロックについては、コンシューマで選ぶ。アナリスト用のエクスポート:全部をドット平坦化する;metadata.preferences.theme はきれいに読める。パイプラインの往復:構造を保つために metadata を Stringify する。CSV パイプラインと組み合わせる完全な jq パターンについては、jq コマンドラインチートシートを参照してほしい。
解説 4:Kubernetes Pod Spec(深いネスト)
kubectl get pod -o json のレスポンスは、フラット戦略にとって最悪のケースだ。構造は日常的に 6 階層の深さに達する(spec.template.spec.containers.0.resources.limits.memory)。素朴なドット平坦化は、70 文字超の列名と 200 列以上の出力を生む。2 つの戦略が有効だ。
**kubectl jsonpath で前射影する。**実際に必要なフィールドだけを選び出す:
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\t"}{.status.phase}{"\n"}{end}' > pods.tsv
spec を Stringify し、metadata を平坦化する。metadata(name、namespace、labels)はフラットに保ち、spec は単一セルへ Stringify する:
kubectl get pods -o json | jq 'map({name: .metadata.name, namespace: .metadata.namespace, spec: (.spec | tostring)})'
そしてコンバータに Flatten モードで貼り付ける。spec 列は 1 つの JSON セルになり、metadata 列は読める状態を保つ。前射影なしで kubectl get pod -o json | json-to-csv flatten を実行するアンチパターンは避ける。列数が手に負えなくなる。
往復安全:Flatten は不可逆、Stringify は可逆
他のガイドが省きがちな前提を先に置いておく。**ドット記法、アンダースコア記法、インデックス配列、行展開はすべて、一方向の射影だ。**いずれかで平坦化すれば、CSV だけから元の JSON を完全に再構築することはできない。
反例は容易に構成できる。customer.address.city という列名は、{"customer": {"address": {"city": "..."}}} と {"customer": {"address.city": "..."}} のあいだで曖昧だ。インデックス配列は可逆に見えるが、CSV は items.0.sku を配列に戻すべきか、数値キーを持つオブジェクトに戻すべきかを述べられない。行展開はグループ化キーを必要とする;order_id がなければ、どの行が同じ親に属していたか分からない。
往復を生き延びるのは Stringify だけだ。ネストした値は JSON 文字列として逐語的に保たれるので、逆コンバータはセルを読み、パースし、元のまま再挿入する。Stringify で変換し、CSV を保存し、CSV to JSON コンバータに貼り付け、Infer types を有効にすれば、入力と同一のバイト列が得られる。
実用上のルール:パイプラインの往復 → Stringify。一回限りの分析やレポート → コンシューマに応じてドット、アンダースコア、行展開。
ブラウザツールでの実行
JSON to CSV コンバータは、5 戦略のうち 2 つを直接公開している:Flatten(ドット記法とインデックス配列を組み合わせる)と Stringify(セル内に構造を保つ)。他の 3 つ(アンダースコア、行展開、SQL ターゲットプリセット)は、前処理を 1 ステップ挟めば実現できる。
典型的なセッションはクリック 5 回で済む:
- 構文エラーが静かな変換失敗にならないよう、JSON フォーマッタで入力を検証する。
- JSON を JSON to CSV コンバータに貼り付ける。変換は即座に実行される。
- Nested を Flatten に設定してドット + インデックスキーを得るか、Stringify にして配列とオブジェクトを単一セルに保つ。
- プリセットを選ぶ:パイプラインには RFC 4180、EU のスプレッドシートには Excel、ウェアハウスには TSV、カンマの多いテキストには Pipe。
- Swap direction をクリックし、Infer types を有効にした CSV to JSON コンバータで Stringify の往復を検証する。
すべてはブラウザ内で動く。PII、社内エクスポート、本番環境のシークレットがページを離れることはない;ページロード後のネットワークリクエストはゼロ。サードパーティのサイトへのアップロードが選択肢にない機微なデータでも安全に扱える。
よくある落とし穴
6 つの失敗モードが繰り返し現れる。
- **列名の爆発。**Kubernetes のスペックや GitHub PR のレビュースレッドは、数百のリーフパスを生む。対処:
jqかkubectl jsonpathで前射影するか、metadata を平坦化しつつ重いサブツリーを Stringify する。 - **配列長の不一致。**行 1 には 3 アイテム、行 2 には 5 アイテム。インデックス配列は行 1 の
items.3.skuとitems.4.skuに空セルを生む。対処:行展開に切り替える。 - **逆変換でインデックスキーが文字列扱いされる。**CSV-to-JSON が
items.0.skuを見たとき、0は厳密には文字列キーだ。一部の逆コンバータは[{"sku": "A"}]ではなく{"0": {"sku": "A"}}を再構築する。対処:往復には Stringify を使う。 - **キー自体に区切り文字が含まれる。**GA4 のイベントには
event_params.keyのように文字通りのドットを含むキーがあり、.での平坦化は曖昧なパスを生む。対処:アンダースコアを使うか、問題のキーをリネームする。拡張キーをサポートする JSON フォーマットの背景は、JSON5 と JSONC フォーマットガイドを参照してほしい。 - **階層ごとに型が異なる。**ある行では
addressがオブジェクトで、別の行ではnull。平坦化は null オブジェクトの箇所に空セルを生む。コンバータの schema notes 警告がこれをフラグするので、下流のコンシューマで検証できる。 - Excel に大きな整数が切り詰められる。
$oidの Long、Twitter のスノーフレーク ID、K8s のresourceVersionは JavaScript の安全範囲(2^53 − 1)を超え、静かに丸められる。Excel はそれらを9.00719925474E+15として表示する。対処:元の JSON で ID を文字列として保持し、BOM を有効化し、Excel プリセットを使う。
FAQ
ネスト JSON を CSV に平坦化する最良の方法は?
ネスト JSON を CSV に平坦化する最良の方法は、下流のコンシューマ次第だ。Excel や Google Sheets にはドット記法を使う。Pandas や BigQuery でデータを集計する場合は行展開を使う。データ損失なしで CSV を JSON に戻す必要がある場合は Stringify を使う。次に読む相手に戦略を合わせる。
JSON 配列を複数の CSV 行に変換するには?
JSON 配列を複数の CSV 行に変換するには、行展開戦略を使う:配列要素 1 つにつき親フィールドを 1 回ずつ重複させ、それぞれを独自の行にする。Pandas では pd.json_normalize(data, record_path='items', meta=['order_id']) が 1 回の呼び出しでこれを行う。SQL では UNNEST(items) が同じ形を生む。親キーは展開された行をまたいで反復する。
CSV を元のネスト JSON に往復させられるか?
CSV を元のネスト JSON に往復させられるのは Stringify モードだけだ。ドット記法、アンダースコア、インデックス配列、行展開は不可逆な一方向の射影で、逆コンバータは木を完全には再構築できない。Stringify は配列とオブジェクトを単一セル内の JSON として保つので、Infer types が有効なら完全な往復はバイト単位で同一だ。
Excel で平坦化した JSON が 1 つの長い列になるのはなぜか?
Excel で平坦化した JSON が 1 つの長い列になるのは、, が小数点に予約され、Excel が区切り文字としてセミコロンを期待するヨーロッパのロケール(ドイツ、フランス、イタリア、スペイン)にいるからだ。json-to-csv の Excel プリセットは、ワンクリックで ; + CRLF + UTF-8 BOM へ切り替わる。
列名にはドット記法とアンダースコアのどちらを使うべきか?
ターゲットが Excel、Google Sheets、Pandas ならドット記法を使う;ドットは json_normalize のデフォルトで自然に読める。ターゲットが SQL ならアンダースコアを使う:Postgres、BigQuery、Snowflake はドットを含む識別子に引用符を要求するが、アンダースコアはどこでも引用符なしで受け入れられる。
pandas の json_normalize はオブジェクトの配列をどう扱うか?
Pandas の json_normalize はオブジェクトの配列を record_path と meta 引数で扱う。pd.json_normalize(data, record_path='items', meta=['order_id']) は items を要素ごとに 1 行へ展開し、order_id を反復する。配列を含まないネストオブジェクトには、より単純な pd.json_normalize(data, sep='_') で customer_address_city のようなアンダースコア区切りの列名を生む。深い木では max_level= で深さを制限する。
深くネストした JSON を平坦化したときの列数の上限は?
深くネストした JSON を平坦化したときの列数の上限は Excel で 16,384、CSV 自体では事実上無制限だが、500 列を超えると出力は扱いきれなくなる。Kubernetes の Pod スペックや GraphQL のレスポンスは容易にこれを超える。JSON to CSV コンバータで重いサブツリーを Stringify するか、jq か kubectl jsonpath で前射影する。
CSV 変換の前段で JSON を平坦化するのに jq は良いツールか?
はい、jq は CSV 変換の前段で JSON を平坦化するのに最適なツールだ。前射影(map({id, name}))、前展開(.[] | {id, item: .items[]})、形状の正規化を 1 行で扱える。jq パイプラインは CSV ステップの前に実行され、どのフィールドをコンバータへ渡すかを正確に制御できる。パターンは jq コマンドラインチートシートにまとめてある。
まとめ
5 つのポイント:
- JSON-to-CSV は構文の問題ではなく、幾何学的な問題だ。木は枝の畳み方を選ばずにグリッドへ収まらない。
- 5 戦略(ドット、アンダースコア、インデックス配列、行展開、Stringify)が実用的な世界を覆う。コンシューマで選ぶ。
- 可逆な経路は Stringify だけだ。パイプラインの往復に使う。
- Excel-EU と BigQuery のプリセットには理由がある。使う。
- 実ペイロード(mongoexport、Kubernetes スペック、GitHub レスポンス)は、たいてい
jqやkubectl jsonpathの前射影ステップを先に挟む必要がある。
自分のペイロードを JSON to CSV コンバータで試してみよう。ローカルで動き、5 戦略すべてを扱い、Stringify で可逆に往復する。アップロード不要、サインアップ不要、データがページを離れることはない。