質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Q&A

解決済

2回答

2352閲覧

階層化されたJSON形式の情報をGoogleAppsScriptでGoogleスプレッドシートへ出力したい

pepe4422

総合スコア5

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

0グッド

1クリップ

投稿2022/10/03 10:19

前提

GoogleAppsScriptでウェブサービスからAPIで情報を取得し、随時Googleスプレッドシートへ出力するアプリケーションを作っています。
本日こちらで質問させていただき、スプレッドシートへの出力は行えたのですが、考慮不足が判明したため、改めて質問させていただきます。

実現したいこと

下記の通りJSON形式で取得した階層化されたデータをGoogleスプレッドシートへproject_idごとに1行に出力したい。
考慮不足であった点は、取得したJSONの配列が階層化されているケースがあることです。
階層化されている情報もスプレッドシートへ出力したく、配列をフラット化する?という下記記事を参考に色々と試行しておりますが、うまく取得することができずどうしたものかと困っております。。。

参考にしているページhttps://codelife.cafe/entry/GAS-JSON-to-SpreadSheet

これを、、、

"data": [
{
"project_id": 1,
"project_name": "XXX",
"custom": [
{
"def_id": 10,
"def_value": "XXXXXX"
}
],
{
"project_id": 2,
"project_name": "ZZZ",
"custom": [
{
"def_id": 20,
"def_value": "ZZZZZZ"
}
],

こうしたい、、、

  A  B  C  D
1 1 XXX  10 XXXXXX
2 2 ZZZ  20 ZZZZZZ
3

発生している問題・エラーメッセージ

「ReferenceError: flattenObj is not defined(行 16」と表示され、処理が止まってしまいます。

該当のソースコード

GoogleAppsScript

1 const sheet_id = 'xxxxxx'; 2 const sheet_name = 'test'; 3 const sheet = SpreadsheetApp.openById(sheet_id).getSheetByName(sheet_name); 4 sheet.getRange("A2:T1000").clearContent(); 5 const response = UrlFetchApp.fetch("https://api.xxxxxx.com/v1.1/projects?limit=10", { 6 "method": "GET", 7 "headers": { 8 "content-type": "application/json", 9 "Api-Key": "xxxxxxx" 10 }, 11 }) 12 const json = JSON.parse(response); 13 14 // 配列内のObjectをフラット化 15 const flatJson = json.data.map((e) => flattenObj(e)); 16 17 // 1つ目の配列のkeyをヘッダーとして定義 18 const headers = Object.data(flatJson[0]); 19 20 // headers をループして生成した配列を body 配列にまとめる 21 const body = flatJson.map((row) => { 22 return headers.map((data) => row[data] || "");s 23}); 24 25 // headers と body を結合 26 const table = [headers].concat(body); 27 28 // setValues 29 sheet.getRange(1, 1, table.length, table[0].length).setValues(table); 30 31 // シートに出力したいデータだけを抜き出して、2次元配列を生成 32 const output = json.data.map(obj => [obj.project_id, obj.project_name, obj.custom.def_id, obj.custom.def_value]); 33 34 // getRange()で使用する値を設定 35 const startRow = sheet.getLastRow() + 1; 36 const rowLength = output.length; 37 const colLength = output[0].length; 38 39 // シートの指定した範囲に、outputを出力する 40 // getRange(開始行番号, 開始列番号, 行数, 列数) 41 sheet.getRange(startRow, 1, rowLength, colLength).setValues(output);

フラット化しての取得にこだわりがあるわけではありませんので、他に良い方法がありましたらどうかご教授の程、お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Cocode

2022/10/03 10:49

今示されているJSON内容の例ですと、そんなに難しいことしなくても、私が前回の質問でお送りしたコードのうち.mapの部分をほんの少し書き換えるだけでできますよー! またはcustomの配列[]の中のオブジェクト{}の数が増減するということですか?
pepe4422

2022/10/03 11:02

Cocode様 今回もご回答ありがとうございます! 難しく考えすぎてしまいましたかね、、またご教授いただけますと助かります。。。 >またはcustomの配列[]の中のオブジェクト{}の数が増減するということですか? →いいえ、customの配列[]の中のオブジェクトの数は変動いたしません。」 よろしくお願いいたします。
Cocode

2022/10/03 11:04

お返事ありがとうございます! 回答に投稿します〜!スマホからなのであまり長文打てませんがすみません。。。
guest

回答2

0

条件が、

  • customの中は必ず配列[]で、
  • その中は必ずオブジェクト{]1つのみでしたら、

前回私がお送りしたコードのmap()の中身少しだけ書き換えたらいけます!

前回 https://teratail.com/questions/p8a4yl1hf851tz

javascript

1const output = json.data.map(obj => [obj.project_id, obj.project_name, obj.custom[0].def_id, obj.custom[0].def_value]);

投稿2022/10/03 11:08

Cocode

総合スコア2314

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

flattenObj という関数を使うことにこだわりがなければ、たとえばこんな感じにすると、スプレッドシート向けの二次元配列 rows が得られます。

javascript

1const resp = JSON.parse(responseJson); 2 3const rows = resp.data.map(({ 4 project_id: A, 5 project_name: B, 6 custom: [{ def_id: C, def_value: D }] 7}) => [A, B, C, D]); 8

実行例:

イメージ説明

追記

参考にしているページ

に掲載されている flattenObj 関数を使うと実現できません、というわけではないのですが、

参考にしているページ

そのままだと一点問題があるので、それについて補足します。

その前にまず質問にある

「ReferenceError: flattenObj is not defined(行 16」と表示され、処理が止まってしまいます。

というエラーになる原因は参考にしているページからflattenObj 関数をコピペし忘れているとかそういうことではないでしょうか?
さて正しく拝借(コピペ)して flattenObj 関数を使えるようになって

javascript

1const flatJson = json.data.map((e) => flattenObj(e));

の行でのエラーが解消されると flatJson は以下のような配列になります。

[ { project_id: 1, project_name: 'XXX', 'custom.0.def_id': 10, 'custom.0.def_value': 'XXXXXX' }, { project_id: 2, project_name: 'ZZZ', 'custom.0.def_id': 20, 'custom.0.def_value': 'ZZZZZZ' } ]

上記のように、配列 custom の先頭要素だったオブジェクトが展開されて、キーが custom.0.def_idcustom.0.def_value という(ちょっとややこしい)文字列になります。

その後、質問にあるコードでは

javascript

1 // 1つ目の配列のkeyをヘッダーとして定義 2 const headers = Object.data(flatJson[0]);

とありますがこれは参考にされているページにもあるように、Object.data は間違いで正しくは Object.keys ですね。

javascript

1 const headers = Object.keys(flatJson[0]);

で、その次に

javascript

1// headers をループして生成した配列を body 配列にまとめる 2const body = flatJson.map((row) => { 3 return headers.map((key) => row[key] || ""); 4});

としているのですが、ここでひとつ問題があります。先のとおり

javascript

1 const headers = Object.keys(flatJson[0]);

として headers を作っていますが、オブジェクトのキーには順序がありません(あるいは「オブジェクトのキーに順序があることを期待したコードは危うい」です。)ので、headers は期待している

[ 'project_id', 'project_name', 'custom.0.def_id', 'custom.0.def_value' ]

という並び順にはなっていない可能性があるものと考えなければなりません。もしこの順には並んでいないとすると

javascript

1// headers をループして生成した配列を body 配列にまとめる 2const body = flatJson.map((row) => { 3 return headers.map((key) => row[key] || ""); 4});

によって得られる body の各行もまた headers の並び順でデータが並ぶことになるので、質問に

こうしたい、、、

とある並びにはならない可能性があります。

これを回避するには

javascript

1 const headers = Object.keys(flatJson[0]);

としないで、配列のリテラルで

javascript

1 const headers = [ 'project_id', 'project_name', 'custom.0.def_id', 'custom.0.def_value' ];

としておくのが確実です。

投稿2022/10/03 11:05

編集2022/10/03 12:27
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Cocode

2022/10/03 11:14 編集

わぁ、これ綺麗ですね!自分の回答よりこちらの方が好きです。
退会済みユーザー

退会済みユーザー

2022/10/03 11:31

ありがとうございます〜😇 分割代入と変数名の変更で => [ A, B, C, D ] にすることでスプレッドシートのデータ行になる配列であることを分かり易くしてみました。基本になるのは Cocode さんの書き方ですね。
pepe4422

2022/10/03 15:48

Cocode様、su507様 お二方ともご回答ありがとうございます! 色々試してみましたが、無事お二方にご教示いただいた方法で出力することができました! が、色々試している過程でまた考慮不足に気が付いてしまいました、JSON全体像をきちんと把握しておきべきでした。。。 実はJSONの全体構成は下記の通りとなっており、"project_custom"配下の情報も出力したいのです。 { "hasMore": true, "data": [ { "project_id": 1, "project_name": "XXXXXX", "custom": [], "customer": { "mail": xxx@aaaa", "name_last": "sss", }, } ], "project_custom": [ { "def_id": 1, "def_name": "AAAAAA" }, { "def_id": 5, "def_name": "BBBBBB" }, { "def_id": 7, "def_name": "CCCCCC" }, ] } flattenObjについては、 >というエラーになる原因は参考にしているページからflattenObj 関数をコピペし忘れているとかそういうことではないでしょうか? と、su507さんのおっしゃる通り、関数のコピペ忘れでした、失礼しました。 コードは動作するようになったのですが、 "project_custom"の情報がうまく取得できず、行き詰ってしまいました。。。 例えば、def_id": 1のdef_nameに入っている情報を"data"配下の情報と紐づけてスプレッドシートへ出力したいのですが、このようなケースではどのような方法があるものでしょうか?
pepe4422

2022/10/07 08:22

Cocode様、su507様 遅くなってしまい申し訳ございません、お二方ともご回答ありがとうございました。 今回はsu507様の方法にて実装いたしました。 大変助かりました、あらためてありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問