RESTAPIを使った一覧データの一括更新

一覧イベントで、各データの顧客コードから顧客管理アプリのある情報を取得して、その情報で更新するという仕組みを作りたいのですが、for文では1行しか実行されません。

他の記事を見ると、配列を用いるというコメントを見つけましたが、今回の場合どのようにするのかわかりません。

ぜひご教示ください。

 

var elrecordNo = kintone.app.getFieldElements('レコード番号');
for (var i = 0; i < elrecordNo.length; i++) {
//レコード情報を取得
var record = event.records[i];
var kokyakucode =record['ルックアップ_顧客コード'].value;
var recordNo = record['レコード番号'].value;
var body = {
"app": 21, //顧客管理アプリ
"query": '文字列_1行_顧客コード="' + kokyakucode + '"'
//"fields": ['対応日時']
};
return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', body).then(function(resp) {
// success
var resrecord = resp.records;

//層別点数の取得
//層別点数から担当仕分けの判定

var body2 = {
"app": 16, //案件プロアプリ
"id": recordNo,
"record": {'ルックアップ_顧客コード': {'value': kokyakucode},
'ラジオボタン_担当仕分け': {'value': tantou}
}
};
//顧客コードの書き込みによりルックアップが更新され、担当仕分けを更新する
return kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body2);
}).then(function(resp2) {
console.log(resp2);
});

}//for終わり
return event;

Promiseを繰り返しやりたい場合は、下記のようにPromise.allを利用するのが良いと思います

https://tech.nerune.co/other/kintone-promise/
※「Lv2. 複数のapi結果を待つ」の章

村濱様

ご回答ありがとうございます。早速記事を見てみました。

まだpromisもthenもあまりよく理解できてないんですが、以下のような流れでしょうか?

1.for内でpromisを作る。

2.promisの中で、(顧客管理アプリからフィールドの値をGETで取得).then(取得した値から担当仕分けを判別).then(判別した担当仕分けをPUTで更新)

3.promisの結果を配列に格納

4.return kintone.Promise.all(promiseAry)でfor内の全ての処理が完了するまで待って、イベントをリターンする

 

まず流れだけを理解したいので、文法やカッコの数に誤りがあるかもしれませんが、無視してください。

thenのつなげ方や、()の囲み先なども自信がありませんが、よろしくお願いいたします。

 

letpromiseAry = [];//結果の配列を作成

for (vari =0; i < elrecordNo.length; i++) {
letcheck =newkintone.Promise(function (resolve, reject) {
kintone.api(kintone.api.url('/k/v1/records',true),'GET', body).(function(resp) {
/*顧客管理アプリからレコード情報を取得*/})
.then(/*層別点数から担当仕分けの判定処理*/) 
.then(//担当仕分けをPUTする処理 
kintone.api(kintone.api.url('/k/v1/record',true),'PUT', body2);}).(function(resp2) {}
);
promiseAry.push(check);//配列に結果を追加
}//for終わり  
  
// 生成したPromiseを全て待つ  
return kintone.Promise.all(promiseAry)   
.then(function () { /\* すでにfor内で全データ更新されているのでイベントをリターンするだけ? \*/   
return event; })  
.catch (function () { event.error = errMsgAry; return event; });   
});

繰り返し自体は、Promiseを配列に格納してPromise.allするというのはあっています。

複数段Promiseしたい場合は下記を参考になるかとおもいます。GETしてからPUTなど。

https://developer.cybozu.io/hc/ja/articles/360023047852-kintone%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8BPromise%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%AE%E5%9F%BA%E6%9C%AC

あと、方法として、一括更新 でもやりたいことはできるのかなとちょっと思いました(やりたいことにかなわない場合はすいません)

教えていただいた参考情報をもとに試行錯誤で無事に動くようになりました!!

当初は途方にくれていましたが、本当にありがとうございます。

最後に今後の参考のために教えていただきたいのですが、ブレイクポイントを設定して処理の流れを確認したところ、以下の動きになりました。結果オーライなのですが、この動き方はどうも理解に苦しむのですが、アドバイスいただけると幸いです。

1.[1]→[5]が一覧件数分ほど繰り返される

2.[2]→[3]→[4]が再度一覧件数分繰り返される

3.最後の[4]が終わったら[6]が実行され、終了する

 

myIndexButton.onclick = function() {

let res=window.confirm('(開発中)現在表示されているページの一覧の層別情報を顧客アプリから一括で取得し、担当仕分けを自動でセットします。よろしいですか?');

if (res==true){//はいをクリックしたとき
var elrecordNo = kintone.app.getFieldElements('レコード番号'); //配列
let promiseAry = [];//結果(Promisオブジェクト)の配列を作成
let errMsgAry = [];
for (var i = 0; i < elrecordNo.length; i++) {
let tantou_set = new kintone.Promise(function (resolve, reject) {

//レコード情報を取得
var record = event.records[i];
var kokyakucode =record['ルックアップ_顧客コード'].value;
var recordNo = record['レコード番号'].value;

var body = {
"app": 21, //顧客管理アプリ
"query": '文字列_1行_顧客コード="' + kokyakucode + '"'
//"fields": ['対応日時']
};
**[1]**
kintone.api(kintone.api.url('/k/v1/records', true), 'GET', body).then(function(resp) {
// success
var resrecord = resp.records;
//層別点数の取得
var shinraido =resrecord[0]['計算_信頼度点数'].value;
var miryokudo =resrecord[0]['計算_魅力度点数'].value;


//層別点数から担当仕分けの判定
**[2]**if(shinraido>7 && miryokudo>5){
var tantou ='営業面談'
}else if(shinraido<8 && miryokudo<6){
var tantou ='事務';
}else{
var tantou ='営業電話';
}//if終わり
console.log(recordNo + ': 信頼度=' + shinraido + '魅力度=' + miryokudo +'⇒' + tantou);
var body2 = {
"app": 16, //案件プロアプリ
"id": recordNo,
"record": {'ルックアップ_顧客コード': {'value': kokyakucode},
'ラジオボタン_担当仕分け': {'value': tantou}
}
};

//顧客コードの書き込みによりルックアップが更新され、担当仕分けを更新する
**[3]**kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body2);
}).then(function(resp2) {
// returnではなく、成功時のハンドラresolveをつかってeventを返却する
**[4]**resolve(event);
}).catch(function(){
errMsgAry.push(resp.message);
reject(event);
});
});//new kintone.Promise終わり
**[5]**promiseAry.push(tantou_set);
}//for終わり
// 生成したPromiseを全て待つ
return kintone.Promise.all(promiseAry)
.then(function () {
/* Promisが全て成功したとき・・・ここではすでにfor内で全データ更新されているのでイベントをリターンするだけ */
window.alert("層別情報の取込と担当仕分けのセットが完了しました。ページの再読み込みを行って、表示を更新してください。");
**[6]**return event;
}).catch (function () {
event.error = errMsgAry;
return event;
});

}else{
window.alert("キャンセルがクリックされました");
}
};//myIndexButton.onclick()終わり

無事うごいたならよかったです!

1.[1]→[5]が一覧件数分ほど繰り返される

2.[2]→[3]→[4]が再度一覧件数分繰り返される

3.最後の[4]が終わったら[6]が実行され、終了する

これですが、JavaScriptには(他の言語もそうですが)、同期的に動くコードと非同期で動くコードがあります。

var a = 1;
var b = 2;
var c = a + b;

という単純なコードは同期的に動く、つまり完全に見た目通りに上から順に動きます。

これに対し、今回で言えばAPIを呼び出すなどネットワークを挟んだり、コードの外に飛び出すようなことは非同期で処理されます(仮にこれを同期的に、純粋に待とうとしてしまうとブラウザが固まってしまうのです、JSの特性的に)

前置きが長くなりましたが、つまり、

  1. forでPromiseを量産する瞬間にAPIに問い合わせを始める(1つ1つリクエストなげるのでなく並列でリクエストなげるイメージ)
  2. ただしコード側ではそのレスポンスを待たずに次の行にいく
  3. promise.allですべての処理がおわるのをまつ

ということになりますので、直感的ではない順番の処理になります。

 

なるほどですね。

コンソールログが、上から順のデータではなくランダムになっていたのは、並列でAPI問い合わせするからということですね。

少しわかってきました。VBAの経験しかない僕にとっては非同期処理という概念を理解する必要がありますね。

とても勉強になりました!ありがとうございました!