レコードのコメント情報を 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 で動作を確認しています。