kintoneのデータをRedashで可視化する

目次

はじめに

kintoneに蓄積した売上データや案件情報などを使ってデータを分析する場合、kintoneのグラフ機能では物足りないから、ファイルに出力してExcelを使っているという方もいらっしゃると思います。

しかし、データ分析するたびにファイル出力しなければなりません。
また一度に出力できるファイルサイズは100MBまでなので、大量のデータを出力するときは分割出力する必要があります。

そんなとき、データを可視化できるツールとkintoneが連携できたら便利かと思います。
この記事では、オープンソースのデータ可視化ツール「 Redash (External link) 」とkintoneを連携し、kintoneで管理しているデータをRedashで可視化する方法を説明します。

kintoneとRedashの連携

RedashとMySQLなどの一般的なデータソースと連携させるには、あらかじめ提供されているコネクタを利用します。
コネクタが用意されていないデータソースに対しても、所定の書式のJSONを返すWebサーブレットを「 Querying URLs (External link) 」で呼び出すことで、外部のアプリケーションからのデータ取得ができます。

kintoneにはRedashのコネクタがないため、この「Querying URLs」というしくみを使ってデータを取得します。

今回、WebサーブレットはGoogle Apps Scriptを使って構築しています。

RedashでアプリIDを指定してクエリを実行すると、RedashからGoogle Apps Scriptへリクエストが送信されます。
Google Apps Scriptはkintone REST APIを実行してレコード情報を取得し、Redash用の書式に整形してRedashへ返します。

事前に必要なもの

  • Redash環境
    この記事では、v6.0.0で確認しています。
  • Googleアカウント
  • kintoneアカウント
information

kintoneアカウントを持っていない方は、1年間無料の「 開発者ライセンス 」を利用してください。

開発の流れ

  1. Google Apps Scriptによるプログラム作成
  2. Redashへのデータソース追加とクエリ作成
  3. おまけ:Query Resultsを使ったフィルターリング

Google Apps Scriptによるプログラム作成

設定方法

  1. Google Apps Script (External link) から、[Start Script]ボタンをクリックします。

  2. 後述のプログラム を貼り付けます。

  3. [ファイル]メニュー >[保存]ボタンをクリックして保存します。
    適当なプロジェクト名(今回は、「kintone-redash-quering-url」)を入力し、[OK]ボタンをクリックします。

  4. [ファイル]メニュー >[プロジェクトのプロパティ]を選択します。
    [プロジェクトのプロパティダイアログ]が表示されるので、[スクリプトのプロパティ]タブを選択します。

  5. [行を追加]リンクをクリックし、次のプロパティを入力します。

    3つすべて入力したら、[保存]ボタンをクリックします。

    プロパティ
    KINTONE_SUBDOMAIN 「xxxxx.cybozu.com」
    kintoneのサブドメインを入力します。
    KINTONE_USER_ID kintoneにログインするユーザー名を入力します。
    対象アプリに閲覧権限をもつユーザーとしてください。
    KINTONE_USER_PASSWORD kintoneにログインするパスワードを入力します。
  6. [公開]メニュー >[Webアプリケーションとして導入]を選択します。

  7. [Webアプリケーションとして導入]ダイアログが表示されます。
    次のように入力し、[導入]ボタンをクリックします。

    項目
    プロジェクトバージョン 「New」を選択します。(初期値)
    次のユーザーとしてアプリケーションを実行 「自分」を選択します。(初期値)
    アプリケーションにアクセスできるユーザー 「全員(匿名ユーザーを含む)」を選択します。
  8. [現在のWebアプリケーションのURL]欄に表示されるURLをメモしておいてください。
    [OK]を押して、ダイアログを閉じます。

    caution
    警告

    このURLにアクセスするとkintoneアプリで保存しているレコード情報を取得できます。  
    URLが外部へ漏れないようにしてください。
    

  9. スクリプトのページは閉じてもかまいません。

    information

    URL発行後に、修正したソースコードを反映する場合は、プロジェクトバージョンを上げる必要があります。  
    4. からの手順で、再度[Webアプリケーションとして導入]ダイアログを表示します。  
    [プロジェクトバージョン]項目で「New」を選択し[更新]ボタンをクリックします。
    

プログラム

以下のプログラムを、Google Apps Scriptに貼り付けてください。

caution
警告

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

  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
/*
 * Redash visualization for kintone sample program
 * Copyright (c) 2019 Cybozu
 *
 * Licensed under the MIT License
*/

/**
 * スクリプトプロパティに保存したkintoneの接続情報を取得する.
 */
const userId = PropertiesService.getScriptProperties().getProperty('KINTONE_USER_ID');
const password = PropertiesService.getScriptProperties().getProperty('KINTONE_USER_PASSWORD');
const subdomain = PropertiesService.getScriptProperties().getProperty('KINTONE_SUBDOMAIN');
/**
 * Redashからのリクエストを受け付ける.
 * @param {Object} e  リクエストパラメータ
 * @return {Object} Redashに返すレスポンス
 */
function doGet(e) {
  const appId = e.parameter.appId;
  if (!appId || appId <= 0) {
    return makeResponse({columns: [], rows: []});
  }
  const records = getKintoneRecords(appId);
  return makeResponse(convertContent4Redash(records));
}
/**
 * kintone REST APIを実行し全件レコードを取得する.
 * @param {string} appIdアプリID
 * @return {Array.<Object>} レコードオブジェクトの配列
 */
function getKintoneRecords(appId) {
  const token = Utilities.base64Encode(userId + ':' + password);
  const baseurl = 'https://' + subdomain + '/k/v1/records.json?app=' + appId + '&query=order by $id asc';
  const options = {
    method: 'GET',
    headers: {'X-Cybozu-Authorization': token}
  };
  return fetch();
  const offset_range = 100;
  // kintoneレコードを取得する
  function fetch(opt_offset, opt_records) {
    const offset = opt_offset || 0;
    let records = opt_records || [];
    const url = baseurl + ' offset ' + parseInt(offset, 10);
    const resp = UrlFetchApp.fetch(url, options);
    const json = JSON.parse(resp.getContentText());
    const respRecord = json.records;
    records = records.concat(respRecord);
    if (respRecord.length === 100) {
      // 残りのレコードを取得する
      return fetch(offset + 100, records);
    }
    return records;
  }
}
/**
 * kintoneレコードの値一覧を取得する.
 * @param {string} appIdアプリID
 * @return {Array} kintoneレコードの値を詰めた配列
 */
function getRecordValues(records) {
  const rows = [];
  for (let i = 0; i < records.length; i++) {
    const record = records[i];
    const row = {};
    for (const key in record) {
      if (Object.prototype.hasOwnProperty.call(record, key)) {
        if (key === '更新者' || key === '作成者') {
          // 「更新者」と「作成者」はプロパティの構造が異なる
          row[key] = record[key].value.code;
        } else {
          row[key] = record[key].value;
        }
      }
    }
    rows.push(row);
  }
  return rows;
}
/**
 * kintoneのフィールド情報一覧を取得する.
 * @param {Object} recordレコード
 * @return {Array} kintoneフィールド情報一覧
 */
function getFieldInfo(record) {
  const columns = [];
  for (const key in record) {
    if (Object.prototype.hasOwnProperty.call(record, key)) {
      const column = {};
      column.name = key;
      column.friendly_name = key;
      if (key === '更新者' || key === '作成者') {
        // 「更新者」と「作成者」はフィールドタイプがないので、強制的に文字列型にする。
        column.type = 'string';
      } else {
        column.type = judgeFieldType(record[key].type);
      }
      columns.push(column);
    }
  }
  return columns;
}
/**
 * kintoneのフィールドタイプをRedashのフィールドタイプに変換する.
 * @param {string} kintoneType kintoneのフィールドタイプ
 * @return {string} Redashのフィールドタイプ
 */
function judgeFieldType(kintoneType) {
  let redashType = '';
  switch (kintoneType) {
    case 'DATETIME':
      redashType = 'datetime';
      break;
    case 'NUMBER':
      redashType = 'float';
      break;
    default:
      redashType = 'string';
      break;
  }
  return redashType;
}
/**
 * Redashへのレスポンスを作る.
 * @param {Object} content Redashで表示できる形式のデータ
 * @return {Object} Redashへのレスポンス
 */
function makeResponse(content) {
  return ContentService.createTextOutput(JSON.stringify(content)).setMimeType(ContentService.MimeType.JSON);
}
/**
 * Redashで表示できる形式のデータに変換する
 * @param {Array} records kintoneのレコード一覧
 * @return {Object} Redashで表示できる形式のデータ
 */
function convertContent4Redash(records) {
  return {columns: getFieldInfo(records[0]), rows: getRecordValues(records)};
}

Redashへのデータソース追加とクエリ作成

  1. Redashを開きます。

  2. 画面右上のユーザー名を選択し、[Data Sources]を選択します。

  3. [+ New Data Source]ボタンをクリックします。

  4. データソースの一覧から[Url]を選択します。

  5. データソースを追加します。
    次のように入力し、[Save]ボタンをクリックします。

    項目
    Name データソースの名前です。
    今回は「kintone」としました。
    URL Base Path 「https://script.google.com/macros/s/」と入力します。
    HTTP Basic Auth Username 空欄
    HTTP Basic Auth Password 空欄
  6. 画面上部の[Create]ボタンをクリックし、[Query]を選択します。

  7. 新規Query画面が表示されます。
    次のように入力し、[Save]ボタンをクリックします。

    項目
    左側のドロップダウン 先ほど追加した「Url」データソースを指定します。
    今回は「kintone」を選びます。
    右側のクエリ画面 「『Google Apps Scriptによるプログラム作成』の手順8. でメモしたURLのhttps://script.google.com/macros/s/以降」
    + 「?appId=」 + 「連携したいアプリID」を指定します。

    たとえば、
    • URL:https://script.google.com/macros/s/xxxxxxx/exec
    • 連携したいアプリID:1
    の場合、入力する値は以下になります。
    xxxxxxx/exec?appId=1
  8. [Execute]ボタンを押下し、データを取得します。
    Google Apps Scriptにリクエストが送られ、返却されたkintoneのデータが表示されます。

これで、Redashからkintoneのデータを閲覧できるようになりました。

あとは「Visualization」機能を使ってグラフを作成したり、グラフを元にダッシュボードを作ってみましょう。
Redashの使い方については、 Redash Help (External link) を参照してください。
Redashでは、こんな2軸グラフを作ることもできます。

Query Resultsを使ったフィルターリング

概要

「URL」データソースで実行されるGoogle Apps Scriptのプログラムは、kintoneのレコード全件を取得します。
そのため、条件で絞ったレコード抽出ができません。

グラフを作る場合、期間が今年などある程度フィルターリングしたデータを使いたいという場面が多いと思います。
その場合、「 Query Results (External link) 」(要v3.0.0以上)というデータソースを使うと、「Url」データソースで取得したデータの絞り込みができます。

Redashでは、クエリの実行結果をとRedashの内部データベースに保存しています。
「Query Results」は内部データベースで保存された実行結果に問い合わせするデータソースです。

手順

  1. Redashを開きます。

  2. 画面右上のユーザー名を選択し、[Data Sources]を選択します。

  3. [+ New Data Source]ボタンをクリックします。

  4. データソースの一覧から[Query Results]を選択します。

  5. データソースを追加します。
    次のように入力し、[Save]ボタンをクリックします。

    項目
    Name データソースの名前です。
    今回は「query-results」としました。
  6. 画面上部の[Create]ボタンをクリックし、[Query]を選択します。

  7. 新規Query画面が表示されます。
    次のように入力し、[Save]ボタンをクリックし、保存します。
    [Execute]ボタンをクリックすると、SQLのWHERE句で指定した条件に一致するデータだけを取得できるようになりました。

    項目
    左側のドロップダウン 先ほど追加した「Url」データソースを指定します。
    今回は「query-results」を選びます。
    右側のクエリ画面 SQLクエリを記述します。
    このとき、FROM句に「query_クエリID>」を指定することで、内部DBに保存されたそのクエリの実行結果を取得できます。

    クエリIDが1の場合は「query_1」になります。

    たとえば、「日時」フィールドが2019年03月01日以降になるデータに絞り込み、かつ「日時」の降順に並び替える場合は、次のようなSQLになります。
    SELECT * FROM query_1 a
    WHERE a.日時 >= '2019-03-01 00:00:00'
    ORDER BY a.日時DESC
information

クエリIDは、「Redashへのデータソース追加とクエリ作成」手順7. で作成したクエリのURLで確認できます。
http://サーバのURL/queries/数字の数字部分がクエリIDです。

おまけ: Query Parameters (External link) 機能を使うと、SQLに条件をべた書きすることなく絞り込み条件を指定できます。

ダッシュボードからも絞り込み条件を指定できます。

おわりに

Redashはオープンソースで利用できる便利なデータ可視化ツールです。

今回紹介した「Url」データソースを使えば、kintoneのデータをRedashに連携できます。
kintoneに蓄積したさまざまなデータをRedashが提供する柔軟なグラフやダッシュボードで可視化できると、データ分析作業の効率化につながるかもしれません。

information

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