📝

google app script から kintone のレコードを更新(レコード番号を指定)

2025/01/20に公開

kintoneのデータを、クエリを使って1件更新するスクリプトです。

はじめに

以下の環境で動作しています。

  • google app script … Chrome V8ランタイム利用
  • kintone … クラウド最新版(2025年1月時点)

用意するもの

他のスクリプトと同じく、google app script → プロジェクトの設定 → スクリプトプロパティ に、以下3つのプロパティを作成します。
それぞれ取得元のアプリにあわせてください。
なお追加先のフィールドコードに「ルックアップ」フィールドがあるか否かでappTokenの記載方法が異なります。

プロパティ名 値(例) 備考
subdomain myDomain アドレス欄https://domainName.cybozu.comにあるdomainName部分
appId 123 レコード追加先のアプリID
appToken ABCDEFG1234567 取得対象アプリで作成したAPIトークン。
「レコード追加」の権限が必要。「レコード閲覧」権限は不要です。
appToken (例外) ABCDEFG1234567,HIJKLMN8901234 追加するデータに フィールド形式:ルックアップ を含む場合は、ルックアップ先アプリの「レコード閲覧」権限があるAPIトークンが必要です。
APIトークン同士は","で区切ります。

更新先アプリ

以下アプリ(例)の任意のレコードを更新します。

フィールド名 フィールドコード フィールド形式 更新したい値
保有資格 qualificationList テーブル 内容は下のテーブルに記載

テーブルのフィールドと、更新したい内容

フィールド名 フィールドコード フィールド形式 更新したい値1 更新したい値2 更新したい値3
資格名 qualificationName 文字列(1行) ITパスポート 簿記2級 基本情報技術者試験
資格取得日 qualificationDate 日付 2020/11/22 2021/02/28 2021/11/21
資格手当 qualificationAmount 数値 0 2000 3000

更新が完了すると、kintoneのサブテーブルが以下のようになるイメージです。

資格名 資格取得日 資格手当
ITパスポート 2020/11/22 0
簿記2級 2021/02/28 2000
基本情報技術者試験 2021/11/21 3000

スクリプト

updateRecordByID.gs
/**
 * サンプルスクリプト
 */
function sampleScript() {
  const qualificationDateValue1 = new Date(2020, 11, 22, 0, 0, 0);
  const qualificationDateValue2 = new Date(2021, 2, 28, 0, 0, 0);
  const qualificationDateValue3 = new Date(2021, 11, 21, 0, 0, 0);
  const updateData = {
    qualificationList: {
      value: [
        {
          value: {
            qualificationName: {
              type: 'SINGLE_LINE_TEXT',
              value: 'ITパスポート',
            },
            qualificationDate: {
              type: 'DATE',
              value: Utilities.formatDate(qualificationDateValue1, 'JST', 'yyyy-MM-dd'),
            },
            qualificationAmount: {
              type: 'NUMBER',
              value: '0',
            },
          }
        },
        {
          value: {
            qualificationName: {
              type: 'SINGLE_LINE_TEXT',
              value: '簿記2級',
            },
            qualificationDate: {
              type: 'DATE',
              value: Utilities.formatDate(qualificationDateValue2, 'JST', 'yyyy-MM-dd'),
            },
            qualificationAmount: {
              type: 'NUMBER',
              value: '2000',
            },
          }
        },
        {
          value: {
            qualificationName: {
              type: 'SINGLE_LINE_TEXT',
              value: '基本情報技術者試験',
            },
            qualificationDate: {
              type: 'DATE',
              value: Utilities.formatDate(qualificationDateValue3, 'JST', 'yyyy-MM-dd'),
            },
            qualificationAmount: {
              type: 'NUMBER',
              value: '3000',
            },
          }
        },
      ]
    },
  }
  const resp = updateRecordByID(1,updateData)
  Logger.log(resp)
}

/**
 * スクリプトプロパティに設定したアプリのレコードを1件更新
 */
function updateRecordByID(recordID, recordData) {
  const subDomain = scriptProperties.getProperty('subdomain')
  const appId = Number(scriptProperties.getProperty('appId'))
  const appToken = scriptProperties.getProperty('appToken')
 
  if (!Number.isInteger(recordID)) {
    throw new TypeError('recordIDは数値で指定してください。');
  }

  const url = `https://${subDomain}.cybozu.com/k/v1/record.json`;
  const options = {
    method: 'PUT',
    headers: {
      'X-Cybozu-API-Token': appToken,
      'Content-Type': 'application/json',
    },
    muteHttpExceptions: true,
    payload: JSON.stringify({
      app: appId,
      id: recordID,
      record: recordData,
    }),
  };

  try {
    const resp = UrlFetchApp.fetch(url, options);
    if (resp.getResponseCode()!==200) {
      throw new Error(`レコード更新エラー:\n HTTPステータス:${resp.getResponseCode()}\n レスポンス :${resp.toString()}`);
    }
    return JSON.parse(resp.getContentText());
  } catch (error) {
    throw new Error(error.message);
  }
}

説明

更新するレコードのフィールドデータを準備

part of updateRecordByID.gs
  const qualificationDateValue1 = new Date(2020, 11, 22, 0, 0, 0);
  const qualificationDateValue2 = new Date(2021, 2, 28, 0, 0, 0);
  const qualificationDateValue3 = new Date(2021, 11, 21, 0, 0, 0);
  const updateData = {
    qualificationList: {
      value: [
        {
          value: {
            qualificationName: {
              type: 'SINGLE_LINE_TEXT',
              value: 'ITパスポート',
            },
            qualificationDate: {
              type: 'DATE',
              value: Utilities.formatDate(qualificationDateValue1, 'JST', 'yyyy-MM-dd'),
            },
            qualificationAmount: {
              type: 'NUMBER',
              value: '0',
            },
          }
        },
        {
          value: {
            qualificationName: {
              type: 'SINGLE_LINE_TEXT',
              value: '簿記2級',
            },
            qualificationDate: {
              type: 'DATE',
              value: Utilities.formatDate(qualificationDateValue2, 'JST', 'yyyy-MM-dd'),
            },
            qualificationAmount: {
              type: 'NUMBER',
              value: '2000',
            },
          }
        },
        {
          value: {
            qualificationName: {
              type: 'SINGLE_LINE_TEXT',
              value: '基本情報技術者試験',
            },
            qualificationDate: {
              type: 'DATE',
              value: Utilities.formatDate(qualificationDateValue3, 'JST', 'yyyy-MM-dd'),
            },
            qualificationAmount: {
              type: 'NUMBER',
              value: '3000',
            },
          }
        },
      ]
    },
  }

今回はレコード番号1の、フィールドコード名qualificationListの内容を更新するようデータを用意しました。
テーブルの場合は[]{}でのネストが多く、しかもキー名valueもそこそこ使うためややこしく感じますが、階層構造さえしっかりイメージできていれば、あとは慣れの問題にできます。
とは言えテーブル内容を更新するコードは頻繁に書かないため、毎回初めましての気分でコーディングしていますので、フィールド形式のページを毎回確認しています。

実際の利用方法としては、この書き方よりもforeach((item)=>{})map((item)=>{})でループして内容を生成するのが多いのではないでしょうか。
その方が効率的かつ動的な内容にも対応させやすいです。


スクリプトプロパティから秘匿した設定を取得

part of updateRecordByID.gs
  const subDomain = scriptProperties.getProperty('subdomain')
  const appId = Number(scriptProperties.getProperty('appId'))
  const appToken = scriptProperties.getProperty('appToken')

ここはいつも通りです。


パラメータ・リクエストヘッダ・リクエストボディの作成

part of updateRecordByID.gs
  const url = `https://${subDomain}.cybozu.com/k/v1/record.json`;
  const options = {
    method: 'PUT',
    headers: {
      'X-Cybozu-API-Token': appToken,
      'Content-Type': 'application/json',
    },
    muteHttpExceptions: true,
    payload: JSON.stringify({
      app: appId,
      id: recordID,
      record: recordData,
    }),
  };

ここも、レコードを追加するときの書き方と大きくは変わりません。
唯一違うのが、payloadの中にid: recordIDが必要なくらいです。


リクエストする

part of updateRecordByID.gs
  try {
    const resp = UrlFetchApp.fetch(url, options);
    if (resp.getResponseCode()!==200) {
      throw new Error(`レコード更新エラー:\n HTTPステータス:${resp.getResponseCode()}\n レスポンス :${resp.toString()}`);
    }
    return JSON.parse(resp.getContentText());
  } catch (error) {
    throw new Error(error.message);
  }

上の「パラメータ・リクエストヘッダ・リクエストボディの作成」が肝になるのでここは他記事と同じですが、GASスクリプト標準のHTTPリクエストUrlFetchApp.fetchを使って外部(kintone)にHTTPリクエストします。
レスポンスコードが200以外はエラーになるので、その場合にはエラーをthrowするようにしています。

Discussion