2019年10月29日火曜日

kintone APIで取り出したJSONデータの重複排除をする

最近、私の所属組織ではkintoneで案件(プロジェクト)管理をしている。
JavaScriptでごりごりカスタマイズしていたりするのだけど、そんな中で備忘録を残しておいたほうがよさそうなネタがあったので投稿。

要件(やりたいこと)
kintoneのプロジェクト一覧アプリに、以下のような情報が入っているとする。

プロジェクト番号客先名案件名担当者名
12345678○×商事株式会社メールシステム構築山田太郎
12345678○×商事株式会社メールシステム構築鈴木花子
23456789▲△自動車株式会社仮想化基盤構築田中勘太郎
※kintoneのアプリは正規化ができないので、1つの案件を複数名で担当する場合、上記のようにプロジェクト番号、客先名、案件名は重複して登録される。

このうち、プロジェクト番号、客先名、案件名の3つをkintone APIで取り出し、重複排除したい(=一意なデータとして取り出したい)というのが今回の要件。

まず、上記のプロジェクト一覧アプリをkintone APIで取り出すと、recordsに以下のようなJSONデータ(オブジェクト値の配列)が入ってくる。
[
 {
  プロジェクト番号: {type: "SINGLE_LINE_TEXT", value: "12345678"},
  客先名: {type: "SINGLE_LINE_TEXT", value: "○×商事株式会社"},
  案件名: {type: "SINGLE_LINE_TEXT", value: "メールシステム構築"}
 },
 {
  プロジェクト番号: {type: "SINGLE_LINE_TEXT", value: "12345678"},
  客先名: {type: "SINGLE_LINE_TEXT", value: "○×商事株式会社"},
  案件名: {type: "SINGLE_LINE_TEXT", value: "メールシステム構築"}
 },
 {
  プロジェクト番号: {type: "SINGLE_LINE_TEXT", value: "23456789"},
  客先名: {type: "SINGLE_LINE_TEXT", value: "▲△自動車株式会社"},
  案件名: {type: "SINGLE_LINE_TEXT", value: "仮想化基盤構築"}
 },
 {
  …
 }
]
これの重複排除をするにはどうすればよいか?
オブジェクト値の配列なので、一工夫必要である(Javascriptにおいてはオブジェクト値を単純に比較演算子やindexOfで評価できないため)。

結論
StackOverflowに頼ってしまいました。
How to remove duplicates from multidimensional array?
このQAは多次元配列のdedupeに関してだが、オブジェクト値の配列にも転用可能。

以下、コード。
StackOverflowのコードをまんまパクらせていただいてるけど、本記事は自分への備忘なのでご勘弁。
オブジェクト値をstringifyし、それをインデックスにした別配列(itemsFound)を使って重複チェックする。

なお、kintoneからのデータ取得には、APIの生使用ではなくkintoneUtilityを利用。
(function() {
  "use strict";
  kintone.events.on(['app.record.index.show'], function(event){
    kintoneUtility.rest.getAllRecordsByQuery({
      app: xx, //プロジェクト一覧アプリのID
      fields: [
        'プロジェクト番号',
        '客先名',
        '案件名',
      ],
    }).then(function(response){
      // 重複排除を行う関数
      function multiDimensionalUnique(arr) {
        var uniques = [];
        var itemsFound = {};
        for(var i = 0, l = arr.length; i < l; i++) {
            var stringified = JSON.stringify(arr[i]);
            if(itemsFound[stringified]) { continue; }
            uniques.push(arr[i]);
            itemsFound[stringified] = true;
        }
        return uniques;
      }

      // ここから本処理
      // kintoneUtilityで取得したデータを重複排除する
      var projects = multiDimensionalUnique(response.records);
      console.dir(projects);

      // 後続処理(略)

    });
    return event;
  });
})();