レコードのコメント情報をCSVでダウンロードする方法

著者名:近本 昌也

目次

はじめに

今回のサンプルでは レコードコメントの一括取得のAPIを利用してレコードのコメント情報をCSV形式でダウンロードしてみました。
レコードのコメント機能が有効になっているお好きなアプリでお試しください。

完成イメージ

CSV出力用のボタンを配置したイメージと、出力対象のコメント一覧は次のとおりです。

出力されたCSVファイル例は次のとおりです。

カスタマイズ

以下の3つのステップでJavaScriptカスタマイズを行い、レコードのコメント情報をCSVでダウンロードしてみましょう。

  1. コメントデータ取得する。
  2. CSV出力用にコメントデータのフォーマットを変更する。
  3. 1と2を組み合わせて作成したCSVファイルをローカルにダウンロードする。

コメントデータ取得する

レコードコメントの一括取得で一度に取得できるコメントは10件までとなります。
そのため、レコード内のコメントを全件取得するためには再帰処理を入れる必要があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * download record comments as CSV sample program
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

const getCommentsData = (opt_offset, opt_comments) => {
  const offset = opt_offset || 0;
  const body = {
    app: kintone.app.getId(),
    record: kintone.app.record.getId(),
    offset: offset
  };
  let comments = opt_comments || [];
  return kintone.api(kintone.api.url('/k/v1/record/comments.json', true), 'GET', body).then((resp) => {
    comments = comments.concat(resp.comments);
    if (resp.older === true) {
      return getCommentsData(offset + 10, comments);
    }
    return comments;
  });
};

フォーマット変更する

次に取得したコメントデータをCSV形式に変換します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
 * download record comments as CSV sample program
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

// エスケープ
const escapeStr = (value) => {
  return '"' + (value ? value.replace(/"/g, '""') : '') + '"';
};
const createCSVData = (comments) => {
  const comments_csv = [];

  // CSVファイルの列名
  const column_row = ['コメントID', 'コメント内容', '投稿日時', '投稿者ログイン名', '投稿者表示名',
    'メンション宛先', 'メンションタイプ'];
  comments_csv.push(column_row);

  for (let i = 0; i < comments.length; i++) {
    const row = [];
    const mentions_code = [];
    const mentions_type = [];

    if (comments[i].mentions[0] === undefined) {
      comments[i].mentions.code = null;
    }
    for (let k = 0; k < comments[i].mentions.length; k++) {
      mentions_code.push(comments[i].mentions[k].code);
      mentions_type.push(comments[i].mentions[k].type);
    }
    row.push(escapeStr(comments[i].id)); // コメントID
    row.push(escapeStr(comments[i].text)); // コメント内容
    row.push(escapeStr(comments[i].createdAt)); // 投稿日時
    row.push(escapeStr(comments[i].creator.code)); // 投稿者ログイン名
    row.push(escapeStr(comments[i].creator.name)); // 投稿者表示名
    row.push(escapeStr(mentions_code.join(','))); // メンション宛先
    row.push(escapeStr(mentions_type.join(','))); // メンションタイプ
    comments_csv.push(row);
  }
  return comments_csv;
};

ダウンロードする

ヘッダーにボタンを追加し、ファイルをダウンロードします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
 * download record comments as CSV sample program
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

// レコード詳細画面
kintone.events.on(['app.record.detail.show'], (event) => {
  // ヘッダの要素にボタンを作成
  const header_element = kintone.app.record.getHeaderMenuSpaceElement();
  const csv_button = document.createElement('button');
  csv_button.id = 'download-comment-csv';
  csv_button.innerText = 'コメントをCSVでダウンロード';
  csv_button.onclick = function() {
    getCommentsData().then((comments) => {
      // CSVデータを作成
      const csv = createCSVData(comments);

      // BOM付でダウンロード
      const csvbuf = csv.map((e) => {
        return e.join(',');
      }).join('\r\n');
      const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
      const blob = new Blob([bom, csvbuf], {type: 'text/csv'});
      const url = (window.URL || window.webkitURL).createObjectURL(blob);

      // ファイル名:アプリ番号_レコード番号.csv
      const appId = kintone.app.getId();
      const recordId = kintone.app.record.getId();
      const fileName = appId + '_' + recordId + '_comments.csv';

      const link = document.createElement('a');
      const e = new MouseEvent('click', {view: window, bubbles: true, cancelable: true});
      link.download = fileName;
      link.href = url;
      link.dispatchEvent(e);
    });
  };
  header_element.appendChild(csv_button);
  return event;
});

応用 レコード一覧画面から全レコードのコメント情報を取得する

応用編として今度は次の処理をしてみました。

  • レコード一覧画面に「CSVでダウンロード」ボタンを配置しダウンロードを可能にする。
  • CSVファイルのフィールドにレコード番号を追加する。(どのレコードのコメントかを分かるようにする為)

完成イメージ

CSV出力用のボタンを配置したイメージと、出力対象のコメント一覧は次のとおりです。

CSV出力例は次のとおりです。

サンプルコード

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * download record comments as CSV sample program
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

(() => {
  'use strict';

  // エスケープ
  const escapeStr = (value) => {
    return '"' + (value ? value.replace(/"/g, '""') : '') + '"';
  };

  // CSVファイルをダウンロード
  const downloadCSV = (csv) => {
    const csvbuf = csv.map((e) => {
      return e.join(',');
    }).join('\r\n');
    const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
    const blob = new Blob([bom, csvbuf], {type: 'text/csv'});
    const url = (window.URL || window.webkitURL).createObjectURL(blob);

    // ファイル名:アプリ番号_comments.csv
    const appId = kintone.app.getId();
    const fileName = appId + '_comments.csv';

    const link = document.createElement('a');
    link.id = 'cscDownLoad';
    const e = new MouseEvent('click', {view: window, bubbles: true, cancelable: true});
    link.download = fileName;
    link.href = url;
    link.dispatchEvent(e);
  };

  // レコード一覧を取得する
  const fetchRecords = (appId, opt_offset, opt_limit, opt_records) => {
    const offset = opt_offset || 0;
    const limit = opt_limit || 100;
    let allRecords = opt_records || [];
    const params = {app: appId, query: 'order by $id asc limit ' + limit + ' offset ' + offset};
    return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params).then((resp) => {
      allRecords = allRecords.concat(resp.records);
      if (resp.records.length === limit) {
        return fetchRecords(appId, offset + limit, limit, allRecords);
      }
      return allRecords;
    });
  };

  // レコード一覧からコメント情報を取得する
  const getCommentCsv = (records, opt_comments, opt_i, opt_offset) => {

    let i = opt_i || 0; // レコードのカウント
    const comments = opt_comments || [];
    const offset = opt_offset || 0;

    const appId = kintone.app.getId(); // アプリID
    const recordId = records[i].$id.value; // レコードID

    const params = {
      app: appId,
      record: recordId,
      offset: offset
    };

    // 一覧画面からコメント取得
    return kintone.api(
      kintone.api.url('/k/v1/record/comments', true), 'GET', params).then((resp) => {

      // CSVデータの作成
      for (let j = 0; j < resp.comments.length; j++) {
        const row = [];
        const mentions_code = [];
        const mentions_type = [];

        if (resp.comments[j].mentions[0] === undefined) {
          resp.comments[j].mentions.code = null;
        }
        for (let k = 0; k < resp.comments[j].mentions.length; k++) {
          mentions_code.push(resp.comments[j].mentions[k].code);
          mentions_type.push(resp.comments[j].mentions[k].type);
        }
        row.push(escapeStr(recordId)); // レコードID
        row.push(escapeStr(resp.comments[j].id)); // コメントID
        row.push(escapeStr(resp.comments[j].text)); // コメント内容
        row.push(escapeStr(resp.comments[j].createdAt)); // 投稿日時
        row.push(escapeStr(resp.comments[j].creator.code)); // 投稿者ログイン名
        row.push(escapeStr(resp.comments[j].creator.name)); // 投稿者表示名
        row.push(escapeStr(mentions_code.join(','))); // メンション宛先
        row.push(escapeStr(mentions_type.join(','))); // メンションタイプ
        comments.push(row);
      }

      // コメントを全て参照したか判定
      if (resp.older) {
        return getCommentCsv(records, comments, i, offset + 10);
      }

      i += 1;
      // レコードを全て参照したか判定
      if (records.length !== i) {
        return getCommentCsv(records, comments, i);
      }
      return comments;
    });
  };

  // コメント一覧のCSVファイルを作成
  const createCSVData = (records) => {
    getCommentCsv(records).then((comments) => {

      const comments_csv = [];
      // CSVファイルの列名
      const column_row = ['レコードID', 'コメントID', 'コメント内容',
        '投稿日時', '投稿者ログイン名', '投稿者表示名',
        'メンション宛先', 'メンションタイプ'];
      if (comments.length === 0) {
        alert('コメントが登録されていません');
        return;
      }
      comments_csv.push(column_row);
      for (let i = 0; i < comments.length; i++) {
        comments_csv.push(comments[i]);
      }
      // BOM付でダウンロード
      downloadCSV(comments_csv);
    });
  };

  // レコード一覧画面
  kintone.events.on(['app.record.index.show'], (event) => {
    // 増殖バグを防ぐ
    if (document.getElementById('download-comment-csv') !== null) {
      return;
    }
    // ヘッダの要素にボタンを作成
    const header_element = kintone.app.getHeaderMenuSpaceElement();
    const csv_button = document.createElement('button');
    csv_button.id = 'download-comment-csv';
    csv_button.innerText = 'コメントをCSVでダウンロード';

    csv_button.onclick = function() {
      fetchRecords(kintone.app.getId()).then((records) => {

        if (records.length === 0) {
          alert('レコードが登録されていません');
          return;
        }
        // CSVデータを作成
        createCSVData(records);

      });
    };
    header_element.appendChild(csv_button);
  });
})();

レコード一括取得時にその結果は1万を超える可能性がある場合には、運用・適用中のプログラムのご確認並びに修正対応の検討をお願いします。
詳細は offsetの制限値を考慮したkintoneのレコード一括取得についてを確認ください。

おわりに

今回は レコードコメントの一括取得を使ってコメント情報をエクスポートするカスタマイズ例を紹介させていただきました。
コメント情報がインポート、エクスポートできることでデータの移行やバックアップとしての利用シーンが増えそうです。

information

このTipsは、2022年12月版kintoneで動作を確認しています。