レコード一括更新で一括で更新されないデータがある

一覧画面で「得意先idセット」ボタンを作成しています。

そのボタンをクリックすると【得意先id】フィールドに【得意先コード】【得意先枝番】を結合した値がセットされ更新する処理です。

例)【得意先コード】15001【得意先枝番】03
【得意先id】1500103

データ数が6000件近くあるので一括で更新をしたいのですが、
ボタンをクリックしても1000件ほどしか更新されず、残りは値がセットされません。

コンソール画面でブレイクしながら処理をみてもデータ数分しっかりとデータ更新の処理をループしていました。

最近javascript をやり始めたばかりの初心者でして
どなたか分かる方がいらしたらご教授いただければ幸いです。
何卒宜しくお願い致します。

(() => {
  'use strict';
  /**
   * kintoneと通信を行うクラス
   */
  var KintoneRecordManager = (function() {
    KintoneRecordManager.prototype.records = [];    // 取得したレコード
    KintoneRecordManager.prototype.appId = null;    // アプリID
    KintoneRecordManager.prototype.query = '';      // 検索クエリ
    KintoneRecordManager.prototype.limit = 100;     // 一回あたりの最大取得件数
    KintoneRecordManager.prototype.offset = 0;      // オフセット

    function KintoneRecordManager() {
        this.appId = kintone.app.getId();
        this.records = [];
    }

    // すべてのレコード取得する
    KintoneRecordManager.prototype.getRecords = function(callback) {
      kintone.api(
        kintone.api.url('/k/v1/records', true),
          'GET',
          {
            app: this.appId,
            query: this.query + (' limit ' + this.limit + ' offset ' + this.offset),
            fields:['レコード番号','得意先コード','得意先枝番']
          },
        (function(_this) {
          return function(res) {
            var len;
            Array.prototype.push.apply(_this.records, res.records);
            len = res.records.length;
            _this.offset += len;
            if (len < _this.limit) { // まだレコードがあるか?
                _this.ready = true;
                if (callback !== null) {
                    callback(_this.records); // レコード取得後のcallback
                }
            } else {
                _this.getRecords(callback); // 自分自身をコール
            }
          };
        })(this)
      );
    };
    return KintoneRecordManager;
  })();
  //レコード一覧画面
  kintone.events.on('app.record.index.show', (event) => {
  
    //増殖バグを防ぐ
    if (document.getElementById('my_index_clientId') !== null) {
      return;
    }
    
    //ボタン要素の作成
    const myIndexButton3 = document.createElement('button');
    //ボタンのid
    myIndexButton3.id = 'my_index_clientId';
    //ボタンに表示される名前
    myIndexButton3.innerText = '得意先idセット';
    //ボタンのCSS
    myIndexButton3.style.backgroundColor = 'rgb(255, 171, 0)';
    myIndexButton3.style.borderRadius = '5px';
    myIndexButton3.style.padding = '10px 15px';
    myIndexButton3.style.fontWeight = 'bold';
    myIndexButton3.style.marginLeft = '10px';
    
    //マウスホバー処理
    myIndexButton3.addEventListener('mouseover' , () => {
      myIndexButton3.style.backgroundColor = 'rgb(255, 241,187 )';
    },false);
    myIndexButton3.addEventListener('mouseleave' , () => {
      myIndexButton3.style.backgroundColor = 'rgb(255, 171, 0)';
    },false);
    
    
    //ボタンクリック時の処理
    myIndexButton3.onclick = () => {
      const message = confirm('得意先idに値をセットします。よろしいですか。');
      if (message) {
        var manager = new KintoneRecordManager();
        manager.getRecords(function(records) {
          // レコード取得後の処理
          console.log(records);

          // 取得したレコードを更新する
          var body = {
            "app": manager.appId,
            "records": []
          };
          var record = {};
          var recordArr = [];
          for (var i = 0; i < records.length; i++) {
            record[i] = {
              "id": records[i]['レコード番号'].value,
              "record": {
                '得意先id': {
                  value:records[i]['得意先コード'].value +
                        records[i]['得意先枝番'].value
                },
              }
            };
            console.log(record[i]);
            recordArr.push(record[i]);
          }
          // 100件ずつ更新
          var s = 0;
          var e = 0;
          while (s < recordArr.length) {
            e = s + 100;
            body.records = recordArr.slice(s, e);
            kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', body, function(resp) {
              // success
              console.log(resp);
            }, function(error) {
              // error
              console.log(error);
            });
            s = s + 100;
          }
          // 再読み込み
          location.reload();
          alert("一括更新が完了しました!!");
        });
      }
    };
    //メニューの右側の空白部分(kintone.app.getHeaderMenuSpaceElement())
    kintone.app.getHeaderMenuSpaceElement().appendChild(myIndexButton3);
  });
})();

REST API をそのまま呼び出すと、非同期で実行されますのでREST API の実行を待たずに、次のステップに進みます。

そのため、レコードの取得や更新完了前にlocation.reload(); が実行されます。

ブレイクしながら処理すると、そちらが優先されて location.reload();されずにループ処理されていると思います。

REST API の実行後に次の処理を行うには、Promise や async/await を使用してください。

 async/await は、IE11 で動作しないという制約がありましたが、IE11 のサポートが終了しましたので今後は async/await でいいと思います。
ただ Promise が必要な場合もありますので、ひととおり目を通しておくことをお勧めします。

kintoneにおけるPromiseの書き方の基本

目指せ!JavaScriptカスタマイズ中級者(2) 〜Promiseのかわりにasync/await編〜

 

rex0220様

コメントありがとうございます。

おかげさまでasync/awaitを使用して無事に一括処理を行うことができました。
大変助かりました!誠にありがとうございます。

以下に変更し処理は無事に一括で行われるようになったのですが、

manager.getRecords( async function(records)  { の行で
△Expected ‘(’ and instead saw ‘function’ とでます。

他にも3つくらい△があちこちに出ております。
こちらはそのままにしていても問題ないでしょうか。

お返事いただけると幸いです
宜しくお願い致します。

//ボタンクリック時の処理
    myIndexButton3.onclick = () => {
      const message = confirm('得意先idに値をセットします。よろしいですか。');
      if (message) {
        var manager = new KintoneRecordManager();
        manager.getRecords( async function(records) {
          // レコード取得後の処理
          console.log(records);

          // 取得したレコードを更新する
          var body = {
            "app": manager.appId,
            "records": []
          };
          var record = {};
          var recordArr = [];
          for (var i = 0; i < records.length; i++) {
            record[i] = {
              "id": records[i]['レコード番号'].value,
              "record": {
                '得意先id': {
                  value:records[i]['得意先コード'].value +
                        records[i]['得意先枝番'].value
                },
              }
            };
            console.log(record[i]);
            recordArr.push(record[i]);
          }
          // 100件ずつ更新
          var s = 0;
          var e = 0;
          while (s < recordArr.length) {
            e = s + 100;
            body.records = recordArr.slice(s, e);
            const resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', body);
            if (resp) {
              // success
              console.log(resp);
            } (error) => {
              // error
              console.log(error);
            };
            s = s + 100;
          }
          // 再読み込み
          location.reload();
          alert("一括更新が完了しました!!");
        });
      }
    };
    //メニューの右側の空白部分(kintone.app.getHeaderMenuSpaceElement())
    kintone.app.getHeaderMenuSpaceElement().appendChild(myIndexButton3);
  });
})();

>manager.getRecords( async function(records)  { の行で
△Expected ‘(’ and instead saw ‘function’ とでます。

これは、エディター上ですか?「アロー関数の ( を予想していたのに function があるよ」ということかな?
実行時に影響が無ければ、問題ないと思います。

あと REST API の offset を指定していますので、レコード1万件以上になる場合は、下記を参照してください。

offset の制限値を考慮した kintone のレコード一括取得について

rex0220様

お返事ありがとうございます。
エディター上になります。

「JSEdit for kintone」 を使用しているのですが、アロー関数にすると
6つくらい同じような文言がでてしまうためfunctionに変更いたしました。
実行時に影響が無のであれば、アロー関数の方がいいでしょうか。

レコード1万件以上の場合についての参照ありがとうございます。
今後1万件を超えることが予想されますので参考にさせていただきます。

 

>実行時に影響が無のであれば、アロー関数の方がいいでしょうか。

書き方の問題なので、好きなほうで。

レコードの定型処理なので、kintone JavaScript Client (@kintone/rest-api-client)のライブラリを使ってもいいと思います。

rex0220様

お返事ありがとうございます。
かしこまりました。

rex0220様がご提示くださった情報をもとにいろいろやって見たいと思います。
ここまでご丁寧に説明してくださりありがとうございました。

また機会がありましたら、何卒宜しくお願い致します。