0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

kintone REST API で一覧の絞り込みを引き継いで、500件を超えてレコードを取る

0
Posted at

kintone の一覧画面に「この一覧を印刷」「この一覧を集計」のようなボタンを置くと、すぐに2つの壁に当たります。

  • 画面に出ているのは1ページ分(20件など)だけ。event.records では全件にならない。
  • REST API のレコード一覧の取得(GET /k/v1/records.json)は、1回で500件まで。

この記事では、建設向けの kintone プラグイン(作業日報の印刷、工程表、原価の予実表、出面の集計、写真台帳)で共通に使っている取り方を、実際のコードで見ます。中身は次の4つです。

  1. 一覧の絞り込みと並び順を、そのまま REST API に渡す
  2. limit と offset で500件ずつ取り、上限で止める
  3. totalCount で「取りきれなかった件数」を知らせる
  4. 添付ファイルを fetch で取り、同時に4本まで読む

コードは2026年11月8日に kintone の開発環境で動かして確かめています。画面の写真は、その環境の架空のデータです。

1. 一覧の絞り込みを引き継ぐ:getQuery と getQueryCondition

利用者が一覧で絞り込んだ条件をそのまま使えると、「印刷したい物だけ先に絞る」という自然な使い方ができます。kintone には、そのための関数が2つあります。

関数 返るもの
kintone.app.getQuery() 絞り込み + 並び順 + limit / offset(いま画面に出ているページ)
kintone.app.getQueryCondition() 絞り込みの条件だけ

並び順も引き継ぎたいときは getQuery() を使い、末尾のページ指定だけを外します(kintone/daily-report/src/js/desktop.js)。

  function listQuery() {
    return (kintone.app.getQuery() || '').replace(/\s*limit\s+\d+(\s+offset\s+\d+)?\s*$/i, '').trim();
  }

getQuery() の末尾には limit 20 offset 0 のようなページ指定が付いているので、それを正規表現で取り除きます。残るのは 作業日 >= "2026-11-01" order by 作業日 asc のような「条件 + 並び順」です。

自分で条件を足したいときは getQueryCondition() を使います。出面(人工)の月次集計では、一覧の絞り込みに「その月」の範囲を足しています(kintone/dezura/src/js/desktop.js)。

    var condition = (kintone.app.getQueryCondition() || '').trim();
    var range = config.date + ' >= "' + month + '-01" and ' + config.date + ' <= "' + month + '-' + pad(daysIn(month)) + '"';
    var query = (condition ? '(' + condition + ') and ' : '') + range + ' order by $id asc';

元の条件を かっこで包んでから and でつなぐのが大事です。元の条件に or が入っていると、かっこがないと優先順位が変わって別の条件になります。

2. 500件ずつ取り、上限で止める

取得は、offset をずらしながら自分を呼び直す形にしています。作業日報の印刷の例です(kintone/daily-report/src/js/desktop.js)。

  var MAX_RECORDS = 100;
  var FETCH_LIMIT = 500;
  // (中略)
  function fetchRecords(query) {
    var collected = [];
    var total = null;
    function step(offset) {
      var size = Math.min(FETCH_LIMIT, MAX_RECORDS - collected.length);
      var body = {app: kintone.app.getId(), query: (query ? query + ' ' : '') + 'limit ' + size + ' offset ' + offset};
      if (offset === 0) body.totalCount = true;
      return kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', body).then(function(response) {
        if (offset === 0 && response.totalCount !== null && response.totalCount !== undefined) total = Number(response.totalCount);
        collected = collected.concat(response.records);
        if (response.records.length < size || collected.length >= MAX_RECORDS) return {records: collected, total: total};
        return step(offset + size);
      });
    }
    return step(0);
  }

読みどころは3つです。

(1) 1回の件数を「残り」で決める。 size = Math.min(500, 上限 − 取った件数) なので、上限ちょうどで止まり、余分に取りません。

(2) 終わりの判定は「返ってきた件数 < 頼んだ件数」。 最後のページは頼んだより少なく返るので、そこで止めます。ちょうど割り切れたときは、もう1回だけ空の結果を取りに行って止まります。

(3) プラグインごとに上限を決める。 同じ関数を、用途に合わせた上限で使っています。

プラグイン 上限 理由
作業日報・KY記録の印刷 100件 1件がA4の1枚。100枚を超える印刷は、絞ってからのほうがよい
原価の予実表(一覧) 2,000件 表の1行が1件で軽い
写真台帳 写真300枚 画像の読み込みが重い
工程表 1,000件 1件が1行。A3横で数ページに収まる量
出面の月次集計 5,000件 1か月分だけを取る。1日に何十件も入るアプリがある

offset で取る方法は、offset が大きくなるほど遅くなり、kintone では offset に上限(10,000)もあります。ここでは上限をどれも5,000件以下にしているので、その範囲に収まります。もっと多く取るときは、$id の大きい順に並べて「前回の最後の $id より小さいもの」を取る方法や、カーソル API を使います。

開発環境の出面のアプリ(1か月に620件)で集計すると、500件と120件の2回に分けて全件を取り、合計が620になりました。

出面の月次集計の画面。レコード620件、延べ620人工と出ている

必要なフィールドだけ取る

原価の予実表では、使うフィールドだけを fields で指定して、通信量を減らしています(kintone/genka/src/js/desktop.js)。

    var fields = ['$id', config.table, actualTable, config.contract, config.project, config.no].filter(function(code, index, all) { return code && all.indexOf(code) === index; });

設定で選ばれなかったもの(空)と、同じコードの重なりを filter で除いています。同じテーブルを2回指定しないようにするためです。

3. totalCount で取りきれなかった件数を知らせる

最初の1回だけ totalCount: true を付けると、条件に合う全件数が返ります。毎回付けると数える手間が増えるので、最初だけにしています。

上限で止めたときは、黙って一部だけ印刷せず、残りの件数を画面に出します(kintone/daily-report/src/js/desktop.js)。

          var notes = [];
          if (found.total !== null && found.total > found.records.length) {
            notes.push('上限' + MAX_RECORDS + '件。残り ' + (found.total - found.records.length) + '件は、絞り込んでから印刷してください');
          }

105件ある一覧で押すと、100件の帳票を作り、上に次のように出ます。

印刷のバー。100件、上限100件。残り5件は、絞り込んでから印刷してください、と出ている

「全部印刷したつもりが途中まで」を防ぐための1行です。

4. 添付ファイルを取る:file.json と同時に4本

写真台帳のプラグインは、添付ファイルの画像を取って台帳に並べます。添付ファイルは GET /k/v1/file.json に fileKey を渡して取ります。中身は JSON ではなくファイルそのものなので、kintone.api ではなく fetch で取ります(kintone/photo-ledger/src/js/desktop.js)。

  function fetchImage(fileKey) {
    var url = kintone.api.urlForGet('/k/v1/file.json', {fileKey: fileKey}, true);
    return fetch(url, {headers: {'X-Requested-With': 'XMLHttpRequest'}, credentials: 'same-origin'}).then(function(response) {
      if (!response.ok) throw new Error('HTTP ' + response.status);
      return response.blob();
    }).then(function(blob) {
      return URL.createObjectURL(blob);
    });
  }
  • kintone.api.urlForGet で、クエリ文字列つきの URL を作れます。第3引数の true はゲストスペースへの対応です。
  • ログイン中のセッションで REST API を呼ぶときは、X-Requested-With: XMLHttpRequest のヘッダーが要ります。kintone.api は自動で付けますが、fetch では自分で付けます。
  • 取った Blob は URL.createObjectURL で <img> に渡し、台帳を閉じるときに URL.revokeObjectURL で解放しています。

300枚を一度に取りに行くと、ブラウザーにも kintone にも負担がかかります。そこで、同時に4本までにしています。

  var CONCURRENCY = 4;
  // (中略)
  function loadImages(photos, onProgress) {
    var next = 0;
    var finished = 0;
    function worker() {
      if (next >= photos.length) return Promise.resolve();
      var photo = photos[next++];
      return fetchImage(photo.file.fileKey).then(function(src) {
        // (中略:img に読み込ませる)
      }).catch(function() {
        photo.failed = true;
      }).then(function() {
        onProgress(++finished);
        return worker();
      });
    }
    var workers = [];
    for (var i = 0; i < CONCURRENCY; i++) workers.push(worker());
    return Promise.all(workers);
  }

開発環境で写真8枚のアプリを開くと、file.json の呼び出しは8回、同時に走ったのは最大4本で、8枚とも表示されました。

4つの「作業者」が、共有の next から次の写真を取っていきます。1枚が終わると同じ作業者が次を取るので、常に4本までしか走りません。1枚が失敗しても catch で印を付けて先へ進むので、全体は止まりません。最後に「読み込み失敗 ○枚」として画面に出しています。

ライブラリーを入れずに、ES5 の範囲(var と Promise)で書いているのは、kintone のプラグインとしてそのまま読み込めるようにするためです。

まとめ

  • 一覧の絞り込みは getQuery() の末尾の limit/offset を外して使う。条件を足すなら getQueryCondition() をかっこで包む。
  • 500件ずつ offset で取り、用途ごとの上限で止める。止めたら totalCount で残りを知らせる。
  • 添付ファイルは file.json を fetch で。X-Requested-With を忘れない。同時に走らせる数は絞る。

ソースと配布先

この記事のコードは kintone プラグイン「作業日報・KY記録プリント」ほか(MIT License)の一部です。入れ方と設定:https://genbakoe.com/kintone/daily-report/?utm_source=qiita&utm_medium=referral&utm_campaign=kintone-rest-api-records-offset / ソース:https://github.com/Genbacoe/kintone-plugins

※ kintone はサイボウズ株式会社の登録商標です。このプラグインと記事は、サイボウズ株式会社の公式のものではありません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?