GASでスプレッドシートのデータをkintoneのアプリに入れたい

スプレッドシートのデータをkintoneのアプリに入れたいのですが、

プログラミング初学者の為お力添えを頂きたいです。

 

具体的には、

GASを利用してスプレッドシートAのシート1、シート2のレコードを1つのkintoneアプリに入れる

という実装を行いたいと思っています。

新たにデータを入れるというよりは、すでにkintoneにあるデータを更新するようなイメージです。

しかしコーディングのイメージが全く湧かず、こちらで質問させていただきました。

 

今回やりたい実装が出来るかどうかも含め、ご教授いただけると幸いです。

http://techblog.sakurug.co.jp/2022/02/21/%E3%80%90gas%E3%80%91%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%8B%E3%82%89kintone%E3%81%AB%E3%83%87%E3%83%BC%E3%82%BF%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E6%96%B9/ 

こちらのページが参考になるかと思います。
ポイントとして、今回ご希望されている処理はレコードの登録(POST)ではなく更新(PUT)になるので、スプレッドシート側にレコードを更新するためのキーとなるフィールドが必要です(レコード番号もしくは重複禁止に指定したフィールド)。

レコードの更新については以下を参考にして下さい。

https://developer.cybozu.io/hc/ja/articles/201941784-%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B4%E6%96%B0-PUT- 

385013133091さま

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

実は昨日、添付いただいたURLを参考に実装を行いました。

POSTにした際はスプレッドシートのデータがkintoneに反映されることは確認できました。

しかし今回やりたいことは更新(PUT)になるのでcybozuの公式ドキュメントも参考に行ってみましたがうまくいっていません。

以下コードになりますので、おかしい部分などご指摘いただけないでしょうか。

function a () {
let sheetName1 = 'シート1';
let sheetName2 = 'シート2';

  createRecords(sheetName1);
  createRecords(sheetName2);
}

function createRecords(sheet) {
  const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet);
  const data = ss.getDataRange().getValues();

  const appId = xxx;
  const apiToken = 'xxx';

  const check = Browser.msgBox('kintoneに登録しますか?', Browser.Buttons.YES_NO);
  
  if (check === 'yes') {
    var records = [];
    for (let i = 1; i < data.length; i++) {
      var record = {
        'フィールドコード1': {'value': data[i][0]}, // ここでレコード番号を指定している
        'フィールドコード2': {'value': data[i][1]},
        'フィールドコード3': {'value': data[i][2]},
      };
    records.push(record);
    }
    addRecords(appId, apiToken, records);
    
    if (record) {
      Browser.msgBox('登録が完了しました');
    } else if (record === undefined) {
      Browser.msgBox('登録可能なデータはありません');
    }
   }
}


function addRecords(appId, apiToken, records) {
  let postUrl = 'https://{サブドメイン}.cybozu.com/k/v1/records.json';
  let postData = {
  'app': appId,
  'records': records,
  };

  const option = {
    'method': 'put',
    'contentType' : 'application/json',
    'headers' : {
      "X-Cybozu-API-Token": apiToken
    },
    'payload': JSON.stringify(postData)
  };
  const req = UrlFetchApp.fetch(postUrl,option);
  return req;
}

現状上記のコードで関数を実行しますと、
Exception: Request failed for https://{サブドメイン}.cybozu.com returned code 400. Truncated server response: {“code”:“CB_VA01”,“id”:“xxxxx”,“message”:“入力内容が正しくありません。”,“errors”:{“records[xxx].id”:{“messages”:["更新するレコードを、「id」か「updateKey」のいずれかのパ… (use muteHttpExceptions option to examine full response)
というエラーメッセージが出てしまいます。
var record の中でレコード番号を指定しているためや、レコード番号をキーとしてkintoneのレコードを更新させたいので、idをパラメータとして指定しなければいけないような気がするのですが、公式ドキュメント等を参考にしてもどのように記述したらいいのか分からずに困っております。

 

 

ki さま
以下のように記載する必要があります。
レコードの更新(PUT)の場合、どのレコードを更新するかを「record(更新したいフィールドを入れた連想配列)」とは別で「id」と指定する必要があり、ここにレコード番号を記載します。
(公式ドキュメントだと「リクエストボディの構造」という部分に例があります)

    var records = [];
    for (let i = 1; i < data.length; i++) {
      var updateRecord = {
        id: data[i][0],
        record: {
          'フィールドコード2': {value: data[i][1]},
        'フィールドコード3': {value: data[i][2]}
        }
      };
      records.push(updateRecord);
    };
    addRecords(appId, apiToken, records);

385013133091さま

ありがとうございます。

recordオブジェクトの中で、日付のデータがあるので(kintone側も日付フィールド)

'フィールドコード2': {value: Utilities.formatDate(data[i][1], 'JST', 'yyyy-MM-dd')}

と指定すると、

Exception: The parameters (String,String,String) don't match the method signature for Utilities.formatDate.

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

 

formatData内の第一引数がDate形式でなければいけないところ、String形式で入ってしまっていることが原因だと思うのですが、

どのように修正をしていいか調べてみていますが分からず…

こちらも教えていただけないでしょうか…。

 

ki さま

表示形式が標準で文字列になるためエラーが発生するかと推察します(表示形式を変更してもkintoneからデータ登録した際に再度標準になります)。
表示形式を変える等でも問題ないと思いますが、日付操作のライブラリ等を導入した方が手軽かと思いますので、以下からDay.jsを追加して
https://gas.excelspeedup.com/dayjs/ 

'フィールドコード2': {value: dayjs.dayjs(data[i][1], 'YYYY/MM/DD').format('YYYY-MM-DD')}

のように記載すれば可能かと思います。

385013133091さま

ありがとうございます。

Day.jsのライブラリを追加し、コードも修正したところ、上記エラーは解消しましたが、今度は

Exception: Request failed for https://{サブドメイン}.cybozu.com returned code 400. Truncated server response: {“code”:“CB_VA01”,“id”:“xxxxx”,“message”:“入力内容が正しくありません。”,“errors”:{“records[xx].record[xx].value”:{“messages”:["日時はISO8601形式の必要があります。

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

該当のフィールドタイプが日時ではなく日付になっているからでしょうか…?

そうであったとしても、フィールドタイプはなるべく変更はしたくないです。

ki さま

日付フィールドでも「日時は…」というエラーが出るようです。
コンソールで日付フィールドに指定したい値がどうなっているか確認できますか?
「Invalid Date」となる場合は日付の形式が違う、もしくは空白である可能性があります。空白である場合は無視する処理を追加しました。

    var records = [];
    for (let i = 1; i < data.length; i++) {
      var updateRecord = {
        id: data[i][0],
        record: {
          'フィールドコード2': {value: data[i][1] ? dayjs.dayjs(data[i][1], 'YYYY/MM/DD').format('YYYY-MM-DD'): ''},
        'フィールドコード3': {value: data[i][2]}
        }
      };
      records.push(updateRecord);
    };
console.log(JSON.stringify(records));

 

mls-hashimotoさま

 

日付フィールドに指定したい値が空欄の場合もあるので

コードを修正したところ、無事にkintone側でレコードの更新が確認できました!

今回も非常に勉強になりました。

ありがとうございます。