カーソルAPIを使っての一覧印刷機能

お世話になります。

javascriptを学び始めたばかりです。

表題のように、カーソルAPIを使用し、数万件のレコードの印刷を考えております。

数万件印刷する事は現実的ではないとは思いますが、実現できるのかなと思い質問させて頂きました。

ネットの情報と自分なりに頭をひねりながらソースを書きましたが、下記のようなエラーが出ました。

Uncaught Error: Invalid properties array for your JSON data.

データとして正しくないようなのですが、よく分からない為、ご教示頂きたいと思います。

また、レコードを取得した後のデータをコンソールログで見ると、全項目を取得していました。

一覧ページに表示しているのは一部の項目で、paramsのfieldsを見ると確かに表示している項目だけを選択しています。

自分の想像としましては、カーソル作成時にqueryやfieldsで抽出されたデータをカーソルに入れ、そこから全データを取得するだけだと思っているのですが違うのでしょうか?

分からない事ばかりで申し訳ありませんが、何卒よろしくお願い致します。

以下ソースになります。

(function() {
    “use strict”;
    kintone.events.on(“app.record.index.show”, function(e) {
      if(e.viewType === ‘custom’) return;
      
      var app = kintone.app.getId();
      var query = kintone.app.getQueryCondition();
      var query2 = kintone.app.getQuery();
      var sort = query2.split(/by|limit/);
      var MAX_READ_LIMIT = 500;
      var viewName = e.viewName;
      
      kintone.api(kintone.api.url(‘/k/v1/app/views’, true), ‘GET’, {app: app}, function(resp) {
        var fields = resp.views[viewName].fields;

        if (fields && fields.length > 0) {
          params.fields = fields;
        }
      });

      var params = {
        app: app,
     query: query + ’ order by’ + sort[1],
        size: MAX_READ_LIMIT
      };

      // カーソルを作成する
      var postCursor = function(_params) {

        var params = _params || {};
        var app = params.app || kintone.app.getId();
        var query = params.query; 
        var size = params.size;
        
        let body = {
          ‘app’: app,
          ‘query’: query,
          ‘size’: size
        }
        
        return kintone.api(kintone.api.url(‘/k/v1/records/cursor.json’, true), ‘POST’, body).then(function(r) {
        return r.id;
        });
      }
    
      //作成したカーソルからレコードを取得する
      var getRecordsByCursorId = function(_params) {

        var params = _params || {};
        var id = params.id;
        var data = params.data;

        if (!data) {
          data = {
            records: []
          };
        }
        
        var body = {
          id: id,
        };
        
        return kintone.api(kintone.api.url(‘/k/v1/records/cursor.json’, true), ‘GET’, body).then(function(r) {
          data.records = data.records.concat(r.records);
          if (r.next) {
            return getRecordsByCursorId({ id: id, data: data });
          }
          return data;
        });
      };
    
      var getRecords = function(_params) {
        return postCursor(_params).then(function(id) {
          return getRecordsByCursorId({ id: id });
        });
      };
    
      //関数の呼び出し
      getRecords(params).then(function(resp) {
        let records = resp.records;
        var list = [];
        for(var i = 0; i < records.length; i++){
          var record = {};
          for(var key in records[i]){
            if(records[i][key].value === null){
                records[i][key].value = ‘’; //nullを文字として表示しないようにする
            }
            record[key] = records[i][key].value;
          }
          list.push(record);
        }

        if (document.getElementById(‘pb’) !== null) return;
        var print_button = document.createElement(‘button’);
        print_button.id = ‘pb’;
        print_button.innerHTML = ‘印刷’;
      
        print_button.onclick = function(){

          printJS({
            printable: list,
            // properties: fields,
            type: ‘json’,
            //見出し。htmlタグが使える
            header: ‘電話帳’,
            //見出しのスタイルを変更したい時
            headerStyle: ‘font-weight: 100; color: #3498db;’,
            //列名のスタイルを変更したい時
            gridHeaderStyle: ‘font-size: 11px; color: #fff; background-color: #3498db; border: 1px solid #3498db;’,
            //グリッドのデータ部分のスタイルを変更したい時
            gridStyle: ‘font-size: 11px; border: 1px solid #3498db; margin-bottom: -1px; white-space: nowrap;’,
            //ページ毎に列名を表示するかどうか。デフォルトはtrue
            repeatTableHeader: false
          });
        };
        
      kintone.app.getHeaderMenuSpaceElement().appendChild(print_button);
      return;
      });
    });
})();
    

>データとして正しくないようなのですが、よく分からない為、ご教示頂きたいと思います。

どのようなデータでエラーになっているか、まず変数の中身を見てみましょう。
kintone JavaScript カスタマイズデバッグまとめ

>また、レコードを取得した後のデータをコンソールログで見ると、全項目を取得していました。

「kintone.api(kintone.api.url(‘/k/v1/app/views’, true), ‘GET’, {app: app}, function(resp) {」が非同期処理なので、

APIの完了を待たずに「params.fields = fields;」をセットする前に、「カーソルを作成する」が実行されるためです。

「params.fields = fields;」をセット後に、「カーソルを作成する」を実行してください。

この処理の一番の問題は、一覧画面表示イベントで無条件に対象レコードを取得してから、ボタン表示を行っていることです。

ボタンがクリックされてからからレコード取得を行いましょう。

一覧画面表示毎に、無駄なレコード取得を行うと下記の影響があります。

・kintone サーバー側の負荷増大
・PC 側の負荷増大
・カーソル多用による、他カーソル利用処理への影響
※カーソルの作成は1ドメインあたり同時に1リクエストのみ実行できます。実行中のリクエストがある場合は待機します。
有効なカーソルの数は1ドメイン辺り10です。
上限に達した場合、次のいずれかが発生するまで新しいカーソルを開くことはできません。

・カーソルでレコード取得中に、画面を切り替えた場合、処理中のカーソルが閉じられずに、10分間残ります。

ご回答頂きありがとうございます。

また、ご連絡が遅くなり申し訳ございません。

非同期処理に対する修正、ボタンがクリックされてからのレコード取得はコードの書き方というか書き順(?)を変更し、

エラーは確認したところ、propertiesの指定をしていなかった事が判明したので指定したところ、印刷ができるようになりました。

ただ、あまりに多いレコード件数になると、「エラー コード: Out of Memory」と出る時があります。(Google Chrome使用)

たまに出ない時もあるのですが、これはパソコンのスペックや、パソコン動作中の不可などによってなるものなのでしょうか?

単純なレコード取得であれば、10万件程度の読み込みも問題なく実行できます。

たぶん、printJS で大量のメモリを使用しているのではないでしょうか?

ブラウザーで使用しているメモリは、表示しているページ・タブ数・JavaScript などにより、大きく変動します。

「エラー コード: Out of Memory」が出たり出なかったりということから、メモリ使用量が制限のぎりぎりのところで動作しているのではないかと思います。

対応策としては、一回の実行で使用するメモリを削減する検討しかなさそうです。

・対象レコードを削減、または分割して印刷

・printJS オプションで使用メモリが変動するか調査・調整

 

 

たしかに取得時ではなく、印刷プレビューを開こうとしている時にエラー表示され止まるので、おっしゃる通りprintJS側だと思います。

とりあえずは絞り込みの方で対象レコードを減らすと問題ないので、これで対応しようかと思います。

この度は的確なご回答を頂き、大変助かりました。

ありがとうございました。

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。