リニューアル後のチュートリアルは次のページを参照してください。
はじめよう kintone API
(著者:落合 雄一)
はじめに
前回、kintone REST APIを利用し、アプリ情報やレコード情報の取得を取り扱いました。
今回は、kintone REST APIを利用したレコードの更新(ルックアップ自動更新)を扱います。頑張っていきましょう\(^o^)/
ルックアップについて
ルックアップは、登録/更新時にコピー元からデータを取得し、コピー先フィールドにデータをコピーします。
しかし、コピー元のデータを更新してもコピー先フィールドは変更されません(>_<)
これは困りましたね・・・
ということで、ルックアップの自動更新にチャレンジしてみましょう(*^^*)
アプリの準備
今回は、顧客マスターアプリと顧客マスターアプリをルックアップしている見積もり管理アプリを使います。
顧客マスターアプリ
下記のような顧客マスターアプリを用意します。
フィールド名 |
フィールドタイプ |
フィールドコード |
備考 |
レコード番号 |
レコード番号 |
レコード番号 |
|
会社 |
文字列(1行) |
company |
必須項目 |
部署 |
文字列(1行) |
post |
|
電話番号 |
リンク |
tel |
入力値の種類:電話番号 |
この顧客マスターアプリにJavaScriptを登録することで、ルックアップの自動更新を実現します。
見積もり管理アプリ
下記のような見積もり管理アプリを用意します。
フィールド名 |
フィールドタイプ |
フィールドコード |
備考 |
ルックアップ |
ルックアップ |
lookup |
関連付けるアプリ:顧客マスター コピー元のフィールド:レコード番号 ほかのフィールドのコピー: 会社⇐[顧客マスター]会社 部署⇐[顧客マスター]部署 電話番号⇐[顧客マスター]電話番号 コピー元のレコード選択時に表示するフィールド: 会社, 部署 |
会社 |
文字列(1行) |
company |
必須項目 |
部署 |
文字列(1行) |
post |
|
電話番号 |
リンク |
tel |
入力値の種類:電話番号 |
テーブル |
テーブル |
Table |
|
テーブル[製品] |
文字列(1行) |
product |
|
テーブル[個数] |
数値 |
個数 |
最小値:0以上 |
テーブル[単価] |
数値 |
単価 |
最小値:0以上 単位:¥ |
テーブル[価格] |
計算 |
price |
計算式:個数*単価 計算式を表示しない 単位:¥ |
小計 |
計算 |
subtotal |
計算式:SUM(price) 計算式を表示しない 単位:¥ |
消費税 |
計算 |
tax |
計算式:subtotal*0.08 計算式を表示しない 単位:¥ |
合計 |
計算 |
total |
計算式:subtotal+tax 計算式を表示しない 単位:¥ |
レコード番号で顧客マスターアプリからルックアップし、会社, 部署, 電話番号をコピーします。
作成できたら、アプリIDは後で使うので控えておいてくださいφ( ̄ー ̄ )メモメモ
実装する処理を整理してみる
コーディングを始める前に、今回やりたいことと、実現するための処理の流れを考えてみましょう!
やりたいこと
- 顧客マスターアプリの情報が更新されたとき、見積もり管理アプリに登録されたデータも更新する
実装する処理
顧客マスターアプリで、レコードが更新されたときに以下の処理を行います。
- 見積もり管理アプリの対象レコードを一括取得
- レコード更新用のデータを準備し、1.の対象レコードを一括更新
- 処理の成功、失敗を知らせるメッセージを表示
別アプリのデータを更新するので、更新処理がうまくいったかどうかを実行後にメッセージでお知らせしましょう!
1~3 は処理の順番を守る必要がある、ということが重要なポイントになってきます。
それでは、JavaScriptの処理を書いていきましょう!
更新時イベント
今回の処理は、顧客マスターアプリのレコード更新時に行います!
レコード保存時に行われるイベントには、「保存するとき(保存ボタンを押したとき)」と「保存に成功した後」の2種類があります。
例:
また、フィールドの設定画面から「必須」や「値の重複の禁止」などを設定しておくと、こちらも保存前にチェックされてエラーメッセージが表示されますね。
ここでは「製品標準の入力チェック」と呼ぶことにします。
これらの保存イベントや製品標準の入力チェックは、下記の順番で実行されます。
- 保存するときのイベントが発生
- 製品標準の入力チェック(必須、重複禁止、型チェック等)
- レコードが保存される
- 保存が成功した後のイベントが発生
第8回は「編集中レコードの値を、保存前に書き換える処理」だったため、1の「保存するときのイベント」を利用しました。
今回は、「入力チェックをすべて通って、レコードに保存された値」を使って別アプリのレコード更新を行う必要があるので、4の「保存に成功した後のイベント」を利用しましょう!
レコードの編集は、レコード画面とレコード一覧画面の2か所で行うことができるため、以下の2つのイベントを使います。
もうお馴染みの形ですね(^^♪
更新が必要なレコードの一括取得
レコードの一括取得は、前回やりましたね(^^♪
「レコード一括取得後の処理」というコメントのところに、このあとやりたい処理を書き足してくことになります。
下記の 2. 3. の部分ですね。
- 見積もり管理アプリの対象レコードを一括取得
- レコード更新(ルックアップの内容を更新)するためのデータを準備
- 2. のデータを使って、見積もり管理アプリの対象レコードを一括更新
2と3は、処理の順番も重要です。
でも先ほどの書き方の中に2と3を組み込んでしまうと、2と3が同時に動いてしまうため処理順が守られません。
そこで、「順番通りに処理を実行してもらう」ために、Promise というJavaScriptの書き方を使います!
Promiseについては、ここでは詳しく解説しませんが、
- 「.then」で順番に実行する処理をつなぐ
- エラーは「.catch」で拾える
ということだけ覚えておいてください。
※Promiseについて勉強したい方は、この記事の最後にリンクを貼っておきますので、そちらをご覧ください。
また、kintone REST APIでの一括取得は、デフォルトで1度に100件までとなりますが、レコードの取得(GET)を参考に「query」パラメータの「limit」オプションを使用することで1度に500件まで取得することができます。
500件以上のルックアップの自動更新を行いたい場合は、「offset の制限値を考慮したレコード一括取得について」などを参考にしてください。今回は100件までの場合のみの説明になります^^;
ルックアップの一括更新
ここで、レコード一括更新のkintone REST APIのドキュメントを確認してみましょう(^^♪
リクエストパラメータ
※パラメータ名 idとupdateKeyのどちらかを指定する必要があります。両方を指定すると、エラーになります。
パラメータ名 | 指定する値 | 必須 | 説明 |
---|---|---|---|
app | 数値又は文字列 | 必須 | アプリの ID を指定します。 |
records | 配列 | 必須 | 更新するレコードの情報を指定します。 本パラメータの値は、更新したいレコードIDと更新したいレコード情報をセットにしたオブジェクトを配列で記述します。 |
records.id | 数値又は文字列 | 省略可 ※updateKeyを指定する際には指定不可 |
更新するレコードの番号。 records 配列内に記述します。 |
records.updateKey | Object | 省略可 ※idを指定する際には指定不可 |
重複禁止フィールドコードと値を指定します。 指定できるフィールドは重複を禁止が設定された文字列(1行)と数値のみです。 |
records.record | Object | 省略可 | レコードの情報(フィールドコードとフィールドの値)をオブジェクトで指定します。 ※フィールド値の仕様についてはフィールドの形式により異なります。 詳細については フィールド形式をご確認ください。 ※省略した場合は、データは更新されません。 |
records.revision | 数値又は文字列 | 省略可 | 期待しているリビジョン番号。 実際のリビジョン番号と一致しない場合はエラーとなります(いずれのレコードも更新しない)。 ただし、値が-1あるいは指定しなかった場合はリビジョン番号の検証を行いません。 |
必要なパラメータは、アプリIDと更新したいレコードIDと更新したいレコード情報をセットにしたオブジェクトですね。
というわけで、更新したいレコードIDと更新したいレコード情報をセットにしたオブジェクトを作成する関数を用意しておきましょう(^^♪
更新するフィールドは、ルックアップのみとなります。
このレコードの更新情報を使ってkintone REST APIで一括更新することで、コピー先フィールドを更新することができます。
ここまで来ると、あとはレコードの一括更新APIを使って更新するだけですね(^^♪
こちらも、Promiseに対応した書き方になっています。
そして更新したいレコードデータは、先ほど書いた「createPutRecords」関数を呼び出して取得しました。
まとめるとこんな感じのJavaScriptになります。
※見積り管理のアプリのアプリIDは環境によって変えてください。
では、このJavaScriptを顧客マスターアプリに登録しレコードの更新を行ってみましょう(^^♪
こんな感じでレコードを編集し保存すると・・・
アラートが表示されましたね!
では、見積もり管理アプリのルックアップしているレコードに更新内容が反映されているか確認してみましょう。
バッチリですね\(^o^)/
最後に
今回は、kintone REST APIを使ってルックアップを自動更新する方法を紹介しました!
しかし、今回のサンプルだと100件までしかルックアップの自動更新ができないので、offset の制限値を考慮した kintone のレコード一括取得についてを参考に実装にチャレンジしてみてください(^^♪
Let’s kintoneカスタマイズ\(^o^)/
参考リンク
このTipsは、2022年7月版 kintone で確認したものになります。
<<第10回 kintone REST APIを利用したレコード取得 | 第12回 jQueryを利用してみよう>>
デモ環境
デモ環境で実際に動作を確認できます。
ログイン情報は cybozu developer network デモ環境 で確認してください。
こちらのおまけに記載がありますが、見積もり管理アプリの編集頻度が高い場合には更新には注意が必要そうですね。
excel読み込みでルックアップ元のレコードを変更した際も、ルックアップ先のレコードは更新されますでしょうか??
田中さん
Excel, CSVでの一括更新ではルックアップ先のレコードは更新されません。
本Tipsに記載していますが、一覧および編集ページでの変更の保存実行前イベントで、ルックアップ先の更新を行っています。
これは、Excel, CSVでの一括更新とは関係ない処理です。
落合さん
承知いたしました。ありがとうございます。
失礼いたします。
こちらのサンプルですが、ルックアップのキーがID取得になっていますが、
文字列をキーにルックアップしている場合はどのように書き換えればよいでしょうか。
JavaScriptを触り始めたばかりなので、できるだけ詳しくご教示いただけますと幸いです。
kanaheyさん
著者の落合です。
第10回までを理解されている方にはご理解いただけるよう説明できているかと思いますが、至らない点をもう少し具体的にご指摘頂けますでしょうか?
文字列をキーにルックアップしている場合ですが、以下のように保存実行時イベントの query 部分を書き換えるとできるかと思います。
以上、参考になりますでしょうか?
ご回答ありがとうございます。
こちら、query部分を文字列フィールドコードに書き換え、
ルックアップフィールドのフィールドコード(サンプルではlookup)を全てこちらが設定したものに書き換えた後に実行しましたが、
record.json の部分で"不正なリクエストです"というエラーが出ます。
こちら、原因等わかれば教えていただきたいです。
横からですが、
は、恐らく
records.json
でないといけない部分が
record.json
となっている等リクエストURLとリクエスト内容の不整合だと思います。
コミュニティの方でご紹介したことがあるかもしれませんが、このようなJavaScriptのデバッグはこちらの方法で、エラー時はerrorというプロパティを見ると原因がすぐ分かることがあります。
(今回の「不正なリクエストです」はerrorプロパティなかったと思いますが)
ご教示いただきありがとうございます。
こちらの表記に誤りがありました。失礼いたしました。
訂正前:record.json の部分で"不正なリクエストです"というエラーが出ます。
訂正後:records.json の部分で"不正なリクエストです"というエラーが出ます。
教えていただいたデバック方法も今後参考にさせていただきたいと思います。
落合様にご教示いただいた、文字列フィールドをキーにしている場合の修正法ですが、
レコード番号をキーにしていた際は動いていたソースでも、
ルックアップの設定を変更し、キーを文字列フィールドに変更すると"不正なリクエストです"とエラーがでてしまいます。
基本は同じですので、コピー元フィールドの重複禁止の設定が漏れているか(これはエラーで分かりやすいメッセージが出ます)、書き換えに失敗しているかですが、もう少し切り分けを進められませんか?
・エラーがGETで起きているのか、PUTで起きているのか
・エラーしている際のリクエスト内容は意図したものになっているのか
これらが押さえられれば原因がわかると思いますが、これらは先にご紹介した方法で確認することが出来ます。お試しいただきましたでしょうか。
失礼いたします。こちらの記事を参考にkintoneでのJavaScriptをさせていただいております。
ルックアップの更新プログラムであげていただいている処理をサンプルソースを参考に作成していたのですが、
どうやら本記事の最後にあがっているルックアップ更新サンプルソースの57行~61行の処理
function(resp) {
var records = resp.records;
// ルックアップの更新
updateLookup(updateAppId, createPutRecords(records));
}
の var records = resp.records;で得られたrecordsをrecords.lengthで確認したところ0となりました。
これは正常な動きなのでしょうか。お分かりになる範囲でよろしいので、ぜひご教授いただけたらと思います。
秋山俊介さん
cstapの落合です。
ルックアップ先のアプリにルックアップしているレコードがないのではないでしょうか?
ご回答ありがとうございます。
「ルックアップ先のアプリにルックアップしているレコードがない」とのお答えをいただいて、
一応確認したのですが、断言はできませんがレコードはある、と思います。
また、同ルックアップ更新サンプルソースの52行目から56行目に該当するコードで
kintone.api.url('/k/v1/records', true),
'GET',
{
"app": updateAppId,
"query": '案件管理の会社名 = "' + event.record.会社名.value + '"'
},
という記述を行っており、ルックアップ先のアプリのルックアップレコードのフィールド名が「案件管理の会社名」、
ルックアップ元の参照されているレコードのフィールド名が「会社名」の状態です。
問題があるとすれば、この記述に何か間違いがあるからだと思われるんですがどうでしょうか。
たびたびにはなりますが、ご教授いただければ幸いです。
queryに使うのは、フィールド名ではなくフィールドコードになります。
フィールドコードを一度確認してみてください。
ご回答ありがとうございます。
先ほどの説明で「フィールド名」と表記したものは、正しくは「フィールドコード」でした
ですので、
ルックアップ先のアプリのルックアップレコードのフィールドコード→「案件管理の会社名」
ルックアップ元の参照されているレコードのフィールドコード→「会社名」
が正しい現在の状態です。
私の説明不備で混乱させてしまい、申し訳ありませんでした。
フィールドコード以外に何かご指摘ありましたら、もう1度ご回答いただければ幸いです。
秋山俊介さん
横ですが、queryで「=」によるGET/recordsは、「すべて」の一覧の絞込における「 =(等しい)」による絞り込みと同じですので、APIのレスポンスとレコード一覧画面からの絞込のレコードが等価になる必要があります。言い方を変えますと、一覧画面で得られる結果に合うようにqueryが指定できれば良いということになります。一覧画面と個数があってるかを見ることで確認しやすくなると思います。
また、queryの指定はJavaScriptであればこちらの方法で自分が意図したqueryとレスポンスになってるか確認しやすくなりますので、リファレンスと合わせて確認頂ければと思います。
ありがとうございます。教えていただいたことを参考にし、ルックアップの自動更新を行うことができました。
原因はqueryで指定した絞り込み条件(フィールド)を変更しようとしてしまっていたために、当初の質問にあったrecords.length→0が起きてしまっていたようです。
queryによる絞り込み条件を別に用意し変更を行ったり、そのままのqueryの絞り込み条件で関連するフィールドを変更してみたところ、正常な動作を行うことができた次第です。
何度も質問させていただきましたが、その都度ご返答くださり、誠にありがとうございました。
まだまだ勉強不足な面がありますが、kintoneを活用させていただきたいと思っておりますので、
いろいろ試していきたいと思います。
ルックアップの自動更新の記事を読ませて頂きました。
一点質問があります。サンプルソースの中で、
record: {
lookup: {
value: record.lookup.value
}
}
の表記が出てきました。
ルックアップのキーとなる項目にアクセスするためには、上記の分を参考にしますと、
kintone.events.on(['app.record.create.submit', 'app.record.edit.submit'], function(event) {
var tblrecord = event.record.テーブル名.value;
var tblrecord2 = tblrecord[行数].value;
var tblrecord3 = tblrecord2[ルックアップのキーのフィールド名].value;
})();
で、あっていますか?
ルックアップによってコピーされるデータは上記のソースで取得できますが、キーとなるフィールドだけundefになります。
キーとコピーされるフィールドへアクセス方法は違うのでしょうか?
よろしくお願いします。
ナカゴウユイエさん
イベントやサブテーブルか否かによって、またルックアップのキーフィールドだからといって、取得方法が異なるといったことはないかと思います。
(全体が見えないので何とも言い難いところはありますが)スニペットをそのまま捉えると、submitイベントの中でアクセスしにいかれているようですが、文字通り保存前のrecord情報にアクセスできるはずです。
記事改訂情報:
2015年11月のアップデートにより、「query」パラメータの「limit」オプションを使用することで1度に500件取得可能な旨を追記いたしました。
サブテーブルにルックアップを設置し、サブテーブル内のフィールドを自動更新したい場合は、
どのようにサンプルコードを変更すればよいでしょうか?
いつも大変お世話になっております。
初心者で大変恐縮でございます。「今回は100件までの場合のみの説明になります」となってますがここで指している100件はどう解釈すればよろしいでしょうか?
今弊社で使っている「顧客情報マスタ」には1500件ぐらいの顧客登録があります。これをルックアップして「出庫管理マスタ」を作成しております。ルックアップになっているため、「顧客情報マスタ」の基本情報(住所、担当者など)が変えた場合、「出庫管理マスタ」には都度都度【取得】で更新しておりますが、掲示のレコード更新では対応可能でしょうか?1回では100件ぐらいの変更はないですが、ここで指している100件は一度で100件更新した場合でしょうか?それとも弊社みないな1500件レコードある場合、100件のみが対応可能という意味でしょうか?回答していただけるとともて助かりますが、どうぞよろしくお願い致します。
goro 様
お世話になっております。
cybozu developer network 事務局です。
>ここで指している100件は一度で100件更新した場合でしょうか?それとも弊社みないな1500件レコードある場合、100件のみが対応可能という意味でしょうか?回答していただけるとともて助かりますが、どうぞよろしくお願い致します。
当記事で説明している100件上限というのは、goro様の環境ですと、
「ある顧客情報マスタのレコードA」をルックアップしている「出庫管理マスタのレコード」が100件以上ある場合、
「A」を更新した際に更新できる「出庫管理マスタのレコード」の上限は '/k/v1/records.json' の GETで、デフォルトで取得できる上限の100件となります。
したがってこの場合、101件目以降は更新ができなくなります。
また、100件以上更新をかけたい場合は記事の案内をご覧ください。
実装についての技術的な問い合わせは、コミュニティをご活用ください。
今度ともよろしくお願いいたします。
いつもお世話になっております。
以下の2箇所だけ自社用に変えました。
変更箇所:
①20行~21行
を
顧客先名コード: {
value: record.顧客先名コード.value
②55行
query: 'lookup = ' + event.record['レコード番号'].value
を
query: '顧客先名コード = "' + event.record['顧客先名コード'].value + '"'
⇒これで起きている不思議な現象として、管理者が顧客マスターアプリを編集したら、”ルックアップの更新が完了しました!”というメッセージは出るが、
他のユーザーがマスターアプリを編集したら、一回目は普通に保存される。もう一度編集画面を開いて、保存をクリックすると”ルックアップの更新が完了しました!”というメッセージがやっと出る。なんででしょうか?なにかアドバイスいただけることは可能でしょうか?どうぞよろしくお願い致します。
goro 様
お世話になっております。cybozu developer network 事務局です。
こちらは記事のフィードバック欄です。
大変恐れ入りますが、技術的な質問についてはコミュニティをご活用ください。
いつもお世話になっております。
知識不足で大変恐縮ではございます。
顧客マスターアプリに登録して、見積もり管理アプリにまだ登録してないときでも顧客マスターアプリに登録したレコードを編集すると更新されましたとなるが、これを見積もり管理アプリにまだ登録してないとかなにか未完成のメッセージを出すことは可能でしょうか?ご指導のほど、よろしくお願い致します。
利絵さま
おそらく、
// 処理成功
alert('ルックアップの更新が完了しました!');
の 直前に、
resp2の中身が0だったらエラーのメッセージを出す という処理を追加するという方針でできるかと存じます。
試していただき、ご質問があった場合はコミュニティを活用いただければ幸いです。
お世話になります。初心者(知識がありません)なのでご教示願います。
サンプルプログラムを実装し、動作確認をおこないました。
「ルックアップの更新が完了しました!」と表示され、"OK”をクリックすると画面が薄暗くなり「更新データ取得中」と表示されたままフリーズしてしまいました。
キーボードF5を押して更新を行うと画面が正常に戻りました。
何が原因なのでしょうか?
サンプルプログラムをそのまま流用し、アプリIDだけしか変更していません。
アドバイスをお願いします。
鍋 様
お世話になっております。
cybozu developer network 事務局です。
こちらでサンプルプログラムの動作確認をいたしましたが、正常に動作することを確認いたしました。
恐れ入りますが、以下の記事を参考に、開発者ツールでエラーメッセージが表示されていないかを確認していただけますでしょうか?
動かない?そんな時はデバッグをしてみよう!入門編
cybouzu Developmet team様
回答ありがとうございました。
consoleでエラー内容は確認しましたが、対処方法がよくわからず断念しました。
いろいろと調べた結果、アプリには複数のプラグイン(フリー)を実装しており、これを全て外すことでフリーズ状態がなくなり、正常動作が確認できました。
アドバイスいただき、ありがとうございました。