kintoneのレコードを更新
この記事では、AUTOROでkintoneのレコードを更新する方法を紹介します。
- kintoneUpdateRecordアクションでレコードを1件更新する
- サブテーブルを含むレコードを1件更新する
- ファイルを添付する
- 繰り返しで1件ずつレコードを更新する
- 複数のレコードを1つのアクションで一括更新する(中級者向け)
※本記事の紹介内容を実装するためには、事前にkintoneとの連携設定を済ませておく必要があります。
連携設定の方法はこちらをご参照ください。
・kintoneと連携
1. kintoneUpdateRecord(レコードを1件更新する)
このアクション更新可能なレコードは、1件のレコードのみとなります。
この章では1件のレコードを更新する方法を紹介します。
なお、複数のレコードを更新する場合は、繰り返し処理でkintoneUpdateRecordアクションを使用するか、ブラウザ系アクションでkintoneにログイン後にInjectScriptアクションで更新する必要があります。これらの方法は後述します。
今回は例として、以下レコードの「行き先」更新してみます。
まずはじめに、更新に使用する基本的な情報を設定します。
- kintoneUpdateRecordを設置します。
- 「プロバイダーID」を設定します。
- 「アプリID」を指定します。
kintoneのレコード更新では、アプリ内のどのレコードを更新するか判定するために、以下いずれかをキーとして使用します。
- アップデートキー(アプリ内で値の重複が禁止されたフィールドの値)
- レコードID(レコード番号)
アプリ内で値の重複が禁止されたフィールドの値をキーにして、更新するレコードを判定する方法です。
この設定は、レコードID設定より優先されます。
- 「アップデートキー」パラメータの右端のkintoneアイコンをクリックします。
- ピッカーからfieldをクリックし、アップデートキーとしたいフィールドを選択します。
(ピッカーには値の重複が禁止されたフィールドのみが表示されています) - ピッカーのvalueに、キーとなる値を入力します。
レコードIDを入力するか、レコードオブジェクトを指定すると、レコードIDをキーにして更新するレコードを判定します。
※レコードオブジェクトの指定については、「繰り返しでレコードを更新する」にて紹介します。
- 「更新レコードID」に任意のIDを入力します。
更新する値を作成します。
- 「更新レコード」パラメータの右端のkintoneアイコンをクリックします。
- ピッカーのfieldに、更新するフィールドを入力します。
- ピッカーのvalueに、指定したfieldを更新する値を入力します。
サブテーブルの値は、3のピッカーからは選択できず、kintoneUpdateRecordアクションを使っても更新ができません。
サブテーブルの更新はHTTPRequestアクションで可能です。方法は「2.サブテーブルの値を更新する」をご参照ください。
# レコードを1件更新する +kintone_update_record_1: action>: kintoneUpdateRecord provider: '' appId: '' updateKey: '' recordId: '' record: '' meta: display:
2. サブテーブルの値を更新する(レコード1件)
2022年8月現在、サブテーブルの値は、kintoneUpdateRecordアクションでは更新ができません。
サブテーブルの値を更新する場合は、以下いずれかの方法で対応する必要があります。
- HTTPRequestアクションを使用する
- InjectScriptアクションを使用する
方法は以下となります。
今回は例として、以下レコードのサブテーブルに既に存在する1行の値を変更してみます。
- RunScriptアクションを設定します。
- サブテーブルを含むレコード1件を、kintoneで定められた形式で記述します。
- StoreValueアクションを追加します。
- 変数名は任意とします。
- 値にRunScriptアクションのアウトプットを指定します。
- kintoneから、更新したいレコードが存在するアプリの設定画面を開きます。
- 「設定」タブから、「APIトークン」をクリックします。
- APIトークンが存在しない場合、「生成する」をクリックします。
- APIトークンのアクセス権を設定します。
- 画面左上の「保存」をクリックします。
- 「アプリを更新」をクリックします。
- HTTPRequestアクションを設定します。
- 「URL」を以下とします。
https://サブドメイン名.cybozu.com/k/v1/record.json
- リクエストボディを以下とします。
${1で作成した変数名}
- 「リクエストメソッド」をPUTとします。
- 「ヘッダ」を以下とします。
{"X-Cybozu-API-Token":"2でコピーしたAPIトークン"}
サブテーブル更新のためにInjectScriptアクションを使用する場合、InjectScriptアクションの前に、OpenBrowserアクションからkintoneにログインしておく必要があります。
InjectScriptアクション内部では、kintone REST APIのJavaScriptをそのままご使用いただけます。
加えて、InjectScript内部のスクリプトでasync/awaitを使用すると、kintone REST APIからのレスポンスを出力できます。(参考リンク)
実際のワークフロー例は、下記のワークフロー実行結果のうち「InjectScript(kintone REST API)」タブをご参照ください。
※ログインするユーザーには、該当アプリのレコードを編集する権限が必要です。(参考リンク)
※InjectScriptを使用する場合は、HTTPRequestで必要なAPIトークンの発行は不要です。(参考リンク)
※kintoneにIPアドレス制限がされている場合は、制限を解除頂くか、AUTOROオプションの固定IPサービスをご利用ください(参考リンク)
# スクリプトを実行_レコードを生成 +run_script_1: action>: RunScript code: "return {\n app: アプリID,\n id: 更新対象レコードのID,\n record: {\n 費用: {\n value: [\n {\n id: 32,\n value: {\n おやつ代: {\n value: 300\n },\n 宿泊費: {\n value: 5400\n },\n 交通費: {\n value: 420\n }\n }\n }\n ]\n }\n }\n};\n" # 変数に保存 +store_value_1: action>: StoreValue key: reqBody value: +run_script_1 # HTTPリクエスト +h_t_t_p_request_1: action>: HTTPRequest url: 'https://サブドメイン名.cybozu.com/k/v1/record.json' params: ${reqBody} method: PUT headers: X-Cybozu-API-Token: '2でコピーしたAPIトークン' multipart: false
# スクリプトを実行 +run_script_1: action>: RunScript code: "return {\n app: 8,\n id: 5,\n record: {\n 費用: {\n value: [\n {\n id: 32,\n value: {\n おやつ代: {\n value: 300\n },\n 宿泊費: {\n value: 8400\n },\n 交通費: {\n value: 420\n }\n }\n }\n ]\n }\n }\n};\n" # 変数に保存 +store_value_1: action>: StoreValue key: reqBody value: +run_script_1 # ブラウザを開く_kintoneログイン画面 +open_browser_1: action>: OpenBrowser url: 'https://サブドメイン名.cybozu.com' lang: 'ja-JP' timeZone: 'Asia/Tokyo' headless: true windowSize: '1280 x 720' useShadowDomSelector: false # 文字入力_ユーザーID +type_text_1: action>: TypeText browser: +open_browser_1 selector: '#username-\3A 0-text' text: 'ログインユーザーID' clearValue: false ignoreError: true # パスワード入力 +type_password_1: action>: TypePassword browser: +type_text_1 selector: 'input[type=password]' password: '' ignoreError: true # キーを送信_ログイン +send_keys_1: action>: SendKeys browser: +type_password_1 selector: 'input[type=password]' keys: ["Enter"] ignoreError: true # URLへ遷移_更新したいアプリ +go_to_1: action>: GoTo browser: +send_keys_1 url: 'https://サブドメイン名.cybozu.com/k/アプリID' # ページ内でJavaScriptを実行する_レコードを更新(1件) +inject_script_1: action>: InjectScript browser: +go_to_1 code: "(async () => {\n const appId = kintone.app.getId();\n const paramPut = ${JSON.stringify(reqBody)} //リクエストボディに相当します。StoreValueアクションで定義された変数名をこの記法で代入するか、injectScriptアクション内に直接レコードオブジェクトを生成ください。\n const putResp = await kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', paramPut).catch(e => e.message)\n\n return putResp;\n})()" returnValue: true
3. ファイルを添付する
kintoneUpdateRecordアクションでは、添付ファイルフィールドにファイルを添付することが可能です。
複数のファイル添付も可能です。
ただし、ファイルを添付してレコードを更新する場合、下記の「既存のファイルを保持したまま新しいファイルを追加する」に記載した方法でファイル更新を行わないと、そのレコードに元々添付されていたファイルは消えてしまいます。
- 事前に「更新レコード」欄以外のアプリ等のパラメータを指定したkintoneUpdateRecordアクションを用意しておきます。
- 「更新レコード」からkintoneアイコンをクリックします。
- fieldに、添付ファイルに相当するフィールドを選択します。
- valueに、AUTOROのファイル型アウトプットを指定します。
- OKをクリックします。
- 複数のファイルを取得しておきます。
- CreateListアクションで、複数のファイルをリスト化します。
- kintoneUpdateRecordアクションの「更新レコード」からkintoneアイコンをクリックします。
- fieldに、添付ファイルに相当するフィールドを選択します。
- valueにCreateListのアウトプットを指定します。
- OKをクリックします。
kintoneの仕様により、kintoneのレコード更新においては、あるフィールドのレコードを更新する場合は、そのフィールドにもともとあった値が削除されてしまいます。
※kintoneのレコード更新はPATCHではなくPUTメソッドであるためです。
そのため、添付ファイルフィールドの既存のファイルを保持したままファイルを1つ追加したいような場合は、「更新情報の中に、元の情報(既存のファイル)を全て含ませておく」必要が出てきます。
これをAUTOROで実現する場合、以下のようなワークフローを組む必要が出てきます。
# ファイルを取得 +get_file_1: action>: GetFile provider: local filename: rc_e7a408c6e1be792e5a2b meta: display: filename: label: '00.jpg' icon: text type: chip # 変数に保存_kintoneのサブドメイン https://ここがサブドメイン.cybozu.com/ +store_value_7: action>: StoreValue key: subdomain value: 'kintoneのサブドメイン' # 変数に保存_アプリのAPIトークン +store_value_1: action>: StoreValue key: kintoneToken value: '2で発行したAPIトークン' # レコードを一括取得する +kintone_get_records_1: action>: kintoneGetRecords provider: '' appId: '' fields: [] meta: display: # 各要素について繰り返す_レコード +for_each_1: for_each>: record: +kintone_get_records_1 _do: # ブラウザを開く_使用しているKintoneのログインページ(CORS回避のため) +open_browser_1: action>: OpenBrowser url: 'https://${subdomain}.cybozu.com/login' lang: 'ja-JP' headless: true useShadowDomSelector: false # 変数に保存_既存添付ファイルを格納する配列 +store_value_2: action>: StoreValue key: atacchedFiles value: [] # 各要素について繰り返す_添付ファイル +for_each_2: for_each>: fileKeyData: ${record.添付ファイル} withIndex: hoge2 _do: # ページ内でJavaScriptを実行する_既存ファイルのダウンロード +inject_script_1: action>: InjectScript browser: +open_browser_1 code: "const fileName = \"${fileKeyData.name}\";\nconst url =\n \"https://\" +\n \"${subdomain}\" +\n \".cybozu.com/k/v1/file.json?fileKey=\" +\n \"${fileKeyData.fileKey}\";\nconst xhr = new XMLHttpRequest();\nxhr.open(\"GET\", url);\nxhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\nxhr.setRequestHeader(\"X-Cybozu-API-Token\", \"${kintoneToken}\");\nxhr.responseType = \"blob\";\nxhr.withCredentials = true;\nxhr.send();\nxhr.onreadystatechange = function() {\n // 通信が正常に完了したか確認\n if (xhr.readyState === 4 && xhr.status === 200) {\n const xhrBlob = new Blob([xhr.response], { type: xhr.response.type });\n const blobUrl = URL.createObjectURL(xhrBlob);\n const a = document.createElement(\"a\");\n document.body.appendChild(a);\n a.download = fileName;\n a.href = blobUrl;\n a.click();\n a.remove();\n URL.revokeObjectURL(blobUrl);\n }\n};\n" returnValue: false # ダウンロード完了を待つ_タイムアウトはご調整ください +wait_for_download_1: action>: WaitForDownload timeout: 10000 # ダウンロードファイル一覧 +get_download_files_1: action>: GetDownloadFiles order: DESC sort_by: CREATED # リストから要素を取得_DLされた既存の添付ファイル +get_item_from_list_1: action>: GetItemFromList list: +get_download_files_1 index: '0' # 変数に保存 +store_value_3: action>: StoreValue key: exFile value: +get_item_from_list_1 # 変数に保存_既存のファイルを追加 +store_value_4: action>: StoreValue key: atacchedFiles value: ${atacchedFiles.push(exFile);atacchedFiles} # ブラウザを閉じる +close_browser_1: action>: CloseBrowser browser: +open_browser_1 # 変数に保存_追加したいファイル +store_value_6: action>: StoreValue key: newFile value: '追加したいファイル' # 変数に保存_既存ファイルに新たに添付したいファイルを追加 +store_value_5: action>: StoreValue key: atacchedFiles value: ${atacchedFiles.push(newFile);atacchedFiles} # レコードを1件更新する +kintone_update_record_1: action>: kintoneUpdateRecord provider: '' appId: '' updateKey: '' recordId: ${record} record: 添付ファイル: value: ${atacchedFiles} meta: display:
このワークフローは、以下4点を自分の情報に変更すると実行できます。
- サブドメイン
- APIトークン
- 添付ファイルフィールドのフィールドコード
- 追加したいファイル
4.繰り返しでレコードを更新する
ワークフロー内で取得したkintoneレコードを繰り返し処理で1つずつ加工し、そのレコードを1つずつ更新することも可能です。
更新する値には、スプレッドシートから取得した値や、Webページから取得した値など、AUTOROで利用できる値を使用できます。
ここでは、取得したレコードを加工して、そのレコードを更新する方法を紹介します。
今回は、以下の3つのレコードの「備考欄」に、「行き先」の値の末尾にForEachの繰り返しのインデックスを入れてみます。
- kintoneGetRecordsを設定します。
- 「プロバイダーID」を設定します。
- 「アプリID」に、更新したいレコードが存在するアプリを設定します。
- アクションの詳細を開きます。
- 以下クエリを入力します。
order by $id asc limit 3
- forEachを設定します。
- 「繰り返すリスト」に1のアウトプットを指定します。
- 「要素を格納する変数名」に以下を入力します。
record
- 「繰り返し回数を格納する変数名」に以下を入力します。
index
ここで作成した値で、レコードを更新します。
- StoreValueを設定します。
- 「変数名」に任意の変数名を入力します。
- 「値」を以下とします。
${record["行き先"] + index}
- kintoneUpdateRecordアクションを設定します。
- 「プロバイダーID」を設定します。
- 「アプリID」に、1のレコード取得と同じアプリIDを指定します。
- 「更新レコードID」に以下を入力します。
${record}
- 「更新レコード」パラメータの右端のボタン(ピッカー)をクリックします。
- 「field」から更新したいフィールドの名前を選択します。
- 「value」に以下を入力します。
${3で設定した変数名}
- OKをクリックします。
# レコードを一括取得する +kintone_get_records_1: action>: kintoneGetRecords provider: '' appId: '' fields: [] query: 'order by $id asc limit 3' meta: display: # 各要素について繰り返す +for_each_1: for_each>: record: +kintone_get_records_1 withIndex: index _do: # 変数に保存 +store_value_1: action>: StoreValue key: memo value: ${record["行き先"] + index} # レコードを1件更新する +kintone_update_record_1: action>: kintoneUpdateRecord provider: '' appId: '' updateKey: {} recordId: ${record} record: 備考欄: value: ${memo} meta: display:
サブテーブルを更新する場合は、kintoneUpdateRecordではなく、HTTPRequestアクションをご使用ください。使用方法は2.サブテーブルの値を更新する(レコード1件)をご参照ください。
5.JavaScriptを使用して複数のレコードを一括更新する(上級者向け)
ワークフロー内部でJavaScriptを使用し、kintoneの複数の複数レコードを1つのアクションで一括更新する方法を紹介します。
内容はAUTORO上級者向けとなります。基本的には4.繰り返しでレコードを更新するの方法を推奨いたします。
今回は、JavaScriptでレコードを一括取得し、備考欄の値を「YYYY-MM-DD_HH:mm:ss + 行き先」としてレコードを一括更新します。
- 以下ワークフローをコピーし、エディタモードからペーストします。
- 以下をご自身の環境の情報に更新します。
・サブドメイン名
・ログインID
・ログインパスワード
・更新対象レコードが存在するアプリのURL
# ブラウザを開く_kintoneログイン画面 +open_browser_1: action>: OpenBrowser url: 'https://サブドメイン名.cybozu.com' lang: 'ja-JP' timeZone: 'Asia/Tokyo' headless: true windowSize: '1920 x 1080' useShadowDomSelector: false # 文字入力_ユーザーID +type_text_1: action>: TypeText browser: +open_browser_1 selector: '#username-\3A 0-text' text: 'ユーザーID' clearValue: false ignoreError: true # パスワード入力 +type_password_1: action>: TypePassword browser: +type_text_1 selector: 'input[type=password]' password: '' ignoreError: true # キーを送信_ログイン +send_keys_1: action>: SendKeys browser: +type_password_1 selector: 'input[type=password]' keys: ["Enter"] ignoreError: true # URLへ遷移_更新したいアプリ +go_to_1: action>: GoTo browser: +send_keys_1 url: 'https://サブドメイン名.cybozu.com/k/アプリID'
JavaScriptでレコードを一括取得し、備考欄の値を「YYYY-MM-DD_HH:mm:ss + 行き先」としてレコードを一括更新します。
ワークフローには、レコード更新のレスポンスを出力させます。
- InjectScriptを設定します。
- 以下コードをInjectScript内にコピペします。
(async () => { const appId = kintone.app.getId(); const getReqBody = { app: appId }; const getResp = await kintone .api(kintone.api.url("/k/v1/records", true), "GET", getReqBody) .catch(e => e.message); // putするレコードを作成(備考欄フィールドを更新) const putRecords = getResp.records.reduce((array, currentRecord, i) => { const memo = "${moment().utcOffset(540).format('YYYY-MM-DD_HH:mm:ss ')}" + currentRecord.行き先.value; const record = { id: currentRecord.$id.value, record: { 備考欄: { value: memo } } }; array.push(record); return array; }, []); const putReqBody = { app: appId, records: putRecords }; const putResp = await kintone .api(kintone.api.url("/k/v1/records", true), "PUT", putReqBody) .catch(e => e.message); return putResp; })();
- RunScriptアクションを使用して複数のレコードを作成します。
- 作成した複数のレコードを、kintoneが定めるリクエストボディの形式に加工します。
参考:レコードの更新(PUT) 一括更新 - StoreValueアクションで、作成されたリクエストボディを変数に保存します。
- HTTPRequestアクションを設定します。
- 「URL」を以下とします。1件更新のURLとは異なります。
https://ドメイン名.cybozu.com/k/v1/records.json
- リクエストボディを以下とします。
${先に作成したリクエストボディの変数名}
- 「リクエストメソッド」をPUTとします。
- 「ヘッダ」を以下とします。
{"X-Cybozu-API-Token":"更新対象レコードが存在するアプリのAPIトークン"}
# ブラウザを開く_kintoneログイン画面 +open_browser_1: action>: OpenBrowser url: 'https://サブドメイン名.cybozu.com' lang: 'ja-JP' timeZone: 'Asia/Tokyo' headless: true windowSize: '1920 x 1080' useShadowDomSelector: false # 文字入力_ユーザーID +type_text_1: action>: TypeText browser: +open_browser_1 selector: '#username-\3A 0-text' text: 'ユーザーID' clearValue: false ignoreError: true # パスワード入力 +type_password_1: action>: TypePassword browser: +type_text_1 selector: 'input[type=password]' password: '' ignoreError: true # キーを送信_ログイン +send_keys_1: action>: SendKeys browser: +type_password_1 selector: 'input[type=password]' keys: ["Enter"] ignoreError: true # URLへ遷移_更新したいアプリ +go_to_1: action>: GoTo browser: +send_keys_1 url: 'https://サブドメイン名.cybozu.com/k/アプリID' # ページ内でJavaScriptを実行する_レコードを一括更新 +inject_script_1: action>: InjectScript browser: +go_to_1 code: "(async () => {\n const appId = kintone.app.getId();\n const getReqBody = {\n app: appId\n };\n\n const getResp = await kintone\n .api(kintone.api.url(\"/k/v1/records\", true), \"GET\", getReqBody)\n .catch(e => e.message);\n\n // putするレコードを作成(備考欄フィールドを更新)\n const putRecords = getResp.records.reduce((array, currentRecord, i) => {\n const memo =\n \"${moment().utcOffset(540).format('YYYY-MM-DD_HH:mm:ss ')}\" +\n currentRecord.行き先.value;\n const record = {\n id: currentRecord.$id.value,\n record: {\n 備考欄: {\n value: memo\n }\n }\n };\n array.push(record);\n return array;\n }, []);\n\n const putReqBody = {\n app: appId,\n records: putRecords\n };\n const putResp = await kintone\n .api(kintone.api.url(\"/k/v1/records\", true), \"PUT\", putReqBody)\n .catch(e => e.message);\n return putResp;\n})();\n" waitAfter: 5000 returnValue: true # ページ内でJavaScriptを実行する_ページ更新 +inject_script_3: action>: InjectScript browser: +go_to_1 code: "location.reload();\n" waitBefore: 2000 waitAfter: 5000 returnValue: false # スクリーンショットを撮る +take_screenshot_1: action>: TakeScreenshot browser: +inject_script_3 full_page: false type: png
# 変数に保存_リクエストボディ +store_value_1: action>: StoreValue key: body value: app: 'アプリID' records: [] # レコードを一括取得する_更新関連フィールドのみ +kintone_get_records_1: action>: kintoneGetRecords provider: '' appId: '' fields: ["行き先","備考欄"] meta: display: # 各要素について繰り返す +for_each_1: for_each>: record: +kintone_get_records_1 _do: # スクリプトを実行 +run_script_1: action>: RunScript code: "const now = moment()\n .utcOffset(540)\n .format(\"YYYY-MM-DD_HH:mm:ss \");\nconst updateRecord = createKintoneRecordFormat(record);\nupdateRecord[\"record\"][\"備考欄\"][\"value\"] =\n now + updateRecord[\"record\"][\"行き先\"][\"value\"];\n\nbody.records.push(updateRecord);\nreturn body;\n\n// kintoneリクエスト用にレコードのフォーマットを整える関数です\nfunction createKintoneRecordFormat(argRecord) {\n const recordBody = {};\n Object.keys(argRecord)\n .filter(k => k !== \"$id\")\n .forEach(key => {\n recordBody[key] = {\n value: argRecord[key]\n };\n });\n\n const outputRecord = {\n id: parseInt(argRecord[\"$id\"]),\n record: recordBody\n };\n\n return outputRecord;\n}\n" # HTTPリクエスト_一括更新 +h_t_t_p_request_1: action>: HTTPRequest url: 'https://サブドメイン名.cybozu.com/k/v1/records.json' params: ${body} method: PUT headers: X-Cybozu-API-Token: '更新対象レコードが存在するアプリのAPIトークン' multipart: false