レコード一覧を指定したkintoneのデータを、スプレッドシートに取得したい

背景・実現したいこと

現在、スプレッドシートのGASからAPIを叩き、kintoneのデータをスプレッドシートに取得する実装を行っています。その際、kintoneの一覧を指定してデータを取得したいと思っています。

一覧1~一覧5があれば、一覧2を取得したいといった感じです。

こちらのページ(https://specially198.com/get-kintone-data-into-a-spreadsheet/ )を参考に実装を行いましたが、

【 Exception: Request failed for https://{ サブドメイン }.cybozu.com returned code. Truncade server response: {“code”:“CB_VA01”,“id”{ ランダムな文字列?が記載 }",“message”:“入力内容が正しくありません。”,{“app”:{“messages”:[“整数で指定してください。”]}}}(use muteHttpExceptions option to examine full response) 】

というエラーが起きてしまい、調べても解決出来そうにない為、こちらに投稿させて頂きました。

以下ソースコードです。

function getRecords() {
var urlGetRecords = "http://{サブドメイン}.cybozu.com/k/v1/records.json";
var appId = xxx;var apiToken = 'xxxxxxxxxx'; var viewId = xxxxx;
// kintoneからデータを取得
var paramFields = "&fields=$id," + encodeURIComponent("xxx,xxx,xxx,xxx,xxx");
var url = urlGetRecords + "?app=" + appId + "?view=" + viewId + paramFields;
var res = JSON.parse(UrlFetchApp.fetch(url, {"method": "get","headers": {"X-Cybozu-API-Token": apiToken}}));

// 取得したデータを整形
var output = [];
res["records"].forEach(function(record){
var row = []; row.push(record["xxx"].value));
row.push(record["xxx"].value);
row.push(record["xxx"].value);
row.push(record["xxx"].value);
row.push(record["xxx"].value);
output.push(row);

});

// スプレッドシートに出力
var sheetOutput = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet name');
sheetOutput.getRange(2, 1, output.length, output[0].length).setValues(output);
}

var res = JSON.parse(UrlFetchApp.fetch(url, {"method": "get","headers": {"X-Cybozu-API-Token": apiToken}}));

の部分で引っかかってしまっているようです。

また、console.log(url); を行うと、

http://{サブドメイン}.cybozu.com/k/v1/records.json``?app=xxx?view=xxxxx&fields=$id,以下paramFieldsで取得した値;

となっており、指定したviewIdの取得は出来ているように感じます…

"?view=" + viewId

の記述場所が悪いのかと思い、paramFieldsの後に書いてみる等試してみましたが上手く行きません。

そもそも指定した一覧の取得でview idを指定して取得するという方法が合っているのかも含め教えて頂けたら幸いです。

一覧のviewIdを指定してのリクエストはできません。
同じことを行う場合、HTTPクエリ文字列に「kintoneの一覧に設定されている絞り込み条件」を「&query=」とURLエンコードして繋げる必要があります。

kintoneの一覧(この場合だと一覧2)を開いた状態でコンソールツール等から

kintone.app.getQuery();

を実行すれば一覧の絞り込み条件を取得できるかと思います。

 

varparamFields ="&fields=$id,"+encodeURIComponent("xxx,xxx,xxx,xxx,xxx");
varurl = urlGetRecords +"?app="+ appId +"?view="+ viewId + paramFields;

の部分を

varparamFields ="&fields=$id,"+encodeURIComponent("xxx,xxx,xxx,xxx,xxx");
var query = encodeURIComponent("/\*ここに取得した絞り込み条件を記載\*/");  
varurl = urlGetRecords +"?app="+ appId +"&query="+ query + paramFields;

のように変更すれば可能かと思います。

mls-hashimotoさん、ご回答ありがとうございます。

ここで質問していなかったらずっと悩んだままでした…

本日は実際のコードに触れないので、明日試してみたいと思います。

 

また、実際の実装では先程のソースコードをベースとして、

条件分岐をしてデータを取得したいと思っています。

以下のような感じです。

if (フィールドコード1 === 'xxx' && フィールドコード2 === 'xxx') {

  if (フィールドコード3 === 'xxx') {

    // スプレッドシート1にデータを入れる

  } else if (フィールドコード3 === 'xxx') {

    // スプレッドシート2にデータを入れる

  }

}

条件のところで

record['フィールドコード'].value

と指定すればデータが取得できると思っていたのですが、

そもそもこの方法での実装も実現可能なのでしょうか…?

kintoneもGASも初学者の為初歩的な質問で申し訳ありません。

sk さま
はい、可能です。

構文エラーの修正も含めて作成しましたので以下でお試しください(5~6行目にワークシート名を代入し、7行目の「fields」にスプレッドシートへ挿入したいフィールドコードを順番に入力すれば問題ありません。23~25行目にif文の判定を入れてあります)。

function getRecords() {
  let urlGetRecords = "http://{サブドメイン}.cybozu.com/k/v1/records.json";
  let appId = xxx;
let apiToken = "xxxxxxxxxx";
let sheet1 = "シート1の名前";
let sheet2 = "シート2の名前";
let fields = ["取得するフィールド1", "取得するフィールド2", "他にあれば同じように記載..."];

  // kintoneからデータを取得
  let paramFields = "$id," + encodeURIComponent(String(fields));
  let query = encodeURIComponent("一覧の絞り込み条件");
  let url = urlGetRecords + "?app=" + appId + "&query=" + query + "&fields=" + paramFields;
  let res = JSON.parse(UrlFetchApp.fetch(url, {"method": "get","headers": {"X-Cybozu-API-Token": apiToken}}));

  let outputs = {
    [sheet1]: [],
    [sheet2]: []
  };

  res.records.forEach((record) => {
    let row = fields.map((field) => record[field].value);

  if (record["フィールドコード1"].value == "xxx" && record["フィールドコード2"].value == "xxx") {
      outputs[sheet1].push(row);
  } else if (record["フィールドコード3"].value == "xxx") {
      outputs[sheet2].push(row);
    }
  });

  for (let sheetName in outputs) {
    let sheetOutput = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);

    sheetOutput.getRange(2, 1, outputs[sheetName].length, outputs[sheetName][0].length).setValues(outputs[sheetName]);
  };
};

mls-hashimotoさん、ご回答ありがとうございます。

ご教授いただいたコードで理想の動作が得られました!

ずっと悩んでいたのでとてもすっきりしました。

ありがとうございました。

 

385013133091 さま

先日ご教授いただいたコードについて、

連休明けにif文を入れて実装してみましたが、

21行目の

letrow = fields.map((field) =\>record[field].value);

TypeError: Cannot read property ‘value’ of undefined

というエラーが出てしまいます。

調査してみましたが原因がわからず先に進めないでいます。

大変恐れ入りますが、再度ご教授いただけないでしょうか。

mls-hashimotoさま

立て続けに申し訳ございません。

先ほどのエラーに関してですが、7行目の let fieldsでのフィールドの指定方法が間違っており修正したところ、

今度は

TypeError: Cannot read property 'length' of undefined

というエラーが出てきてしまいました。

こちらも大変恐れ入りますが、ご確認よろしくお願いいたします。

sk さま

21行目のエラーですが、恐らく権限設定で参照できないフィールド、または存在しないフィールドを参照しようとしているのではないかと思います。

    let row = fields.map((field) => {
      console.log(field);
      return record[field].value;
    });

こちらでコンソールにフィールドが表示されるので、エラー前に出たフィールドに問題があるかと思います。

その次に発生しているエラーですが、シート1もしくはシート2に何も挿入するものがない(配列の長さが0)場合に33行目の「outputs[sheetName][0].length」がエラーになっているのではないかと推測します。
挿入するものがない場合の処理を失念しておりました。30行目以降のfor文に回避処理を加えました。

  for (let sheetName in outputs) {
    if (!outputs[sheetName].length) continue;

    let sheetOutput = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);

    sheetOutput.getRange(2, 1, outputs[sheetName].length, outputs[sheetName][0].length).setValues(outputs[sheetName]);
  };

385013133091 さま

ご返信いただきありがとうございます。

ご教授いただいたコードに修正しましたところ、エラーは発生せず実行完了するのですが、

データがシートに振り分けられていません。

kintone上に確かにデータはあり、フィールドコードや値に間違いがないか等確認しましたが、その辺に関しては問題なさそうです。

他に何か考えられる原因はありますでしょうか?

ki さま

問題を特定するためにconsole.logかアラートを入れて何が表示されるかを教えて下さい。

  for (let sheetName in outputs) {
    alert(sheetName, outputs[sheetName].join('・'));

    if (!outputs[sheetName].length) continue;

    let sheetOutput = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);

    sheetOutput.getRange(2, 1, outputs[sheetName].length, outputs[sheetName][0].length).setValues(outputs[sheetName]);
  };

385013133091さま

console.log(sheetName, outputs[sheetName].join('・'));

を行ったところ、sheet1、sheet2に指定したシート名が表示されます。

 

こちら無事に不具合解消しました。

ありがとうございました。

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。