どうも。つじけ(tsujikenzo)です。このシリーズでは「棚卸データの突合」についてお届けしています。全3~4回の今日は3回目です。
前回のおさらい
さて前回は「現場で拾ってくるデータとデータベースのデータ」についてまとめました。必要なデータは出揃ったように見えますが、データの取得をする方法について「列を配列のインデックスで指定すると列の移動や削除があった時に管理が大変💦」という問題が浮かび上がりましたね。
今回は「テーブルを連想配列で取得する」についてお届けします。
SpreadsheetDateConverterToObject
というライブラリがあります。私が作りました💦テーブル(構造化必須)の値を1行目の見出し行と値のキーバリュー方式の連想配列に変換する”便利な”ライブラリです。
今回はこのライブラリを使って2つのテーブル(棚卸表とデータベース)を連想配列型に変換したいと思います。
ライブラリのインストール
スプレッドシート[01_棚卸表]のコンテナバインドにGASを書きたいと思いますので、そちらにライブラリをインストールします。
ライブラリの+をクリックすると[スクリプトID]を入力する欄がありますので、そちらにこのIDを入力して[検索]をクリックします。
Library ID:1s4kGJwF2eG-WGmeqgLWeqQtIBRAXUZbbh3fQ3f7QHvNywubO99nduFIY
このような表が出たらOKです。そのまま[追加]をクリックします。インストールは完了です。
ライブラリを使う
このライブラリには[スプレッドシートID]と[シート名]を渡してあげると、テーブルの全データを連想配列(オブジェクト)型の配列で返してくれる.getElementsArray()メソッドがあります。
実際に[01_棚卸表]でやってみましょう。
const id = '棚卸表のID';
const name = 'シート1';
const comparedValues = SpreadsheetDataConverterToObject.getElementsArray(id, name);
このような配列が取得できます。
comparedValues[行][‘商品ID’]
comparedValues[行][‘賞味期限’]
comparedValues[行][‘納品書番号’]
インデックスで指定していた配列が見出し行のカラム名で指定できようになりました。
同様に[在庫表]でもやってみましょう。
const id = '在庫表のID';
const name = 'シート1';
const originalValues = SpreadsheetDataConverterToObject.getElementsArray(id, name);
無事に取れているようです。
こちらも同様に見出し行のカラム名で値を取得することができます。
originalValues[行][‘商品ID’]
originalValues[行][‘賞味期限’]
originalValues[行][‘納品書番号’]
データの突合(比較)
突合の処理を早める為に、3つのデータを結合します。[01_棚卸表]の3つのデータを結合しましょう。.join()メソッドで一発です。
const joinedCmpValues = comparedValues.map(element => [[element['商品ID'],element['賞味期限'],element['納品書番号']].join(``)]);
もちろん、2つだけのデータを結合することも可能です。
const joinedCmpValues = comparedValues.map(element => [[element['商品ID'],element['納品書番号']].join(``)]);
[在庫表]の3つのデータも結合しましょう。
const joinedOrgValues = originalValues.map(element => [[element['商品ID'],element['賞味期限'],element['納品書番号']].join(``)]);
console.log(joinedOrgValues);
比較しやすいように.flat()メソッドで一次元配列化します。
const cmpValues = joinedCmpValues.flat();
const orgValues = joinedOrgValues.flat();
この2つの配列を比較するのは.filter()メソッドで一発です。.indexOf()メソッドが-1を返す性質を利用します。
const cmpDiffs = cmpValues.filter(element => orgValues.indexOf(element) === -1);
[01_棚卸表]にはあって、[在庫表]にはないデータが抽出されます。
念の為、同様に反対の対象差(symmetric difference)も確認します。
const orgDiffs = orgValues.filter(element => cmpValues.indexOf(element) === -1);
[在庫表]にはあって、[01_棚卸表]にはないデータが抽出されます。
これで、2つのテーブルの突合作業の完成です👏完成したコードはこちらです。
function myFunction() {
let id = '在庫表のスプレッドシートID';
let name = 'シート1';
const originalValues = SpreadsheetDataConverterToObject.getElementsArray(id, name);
id = '01_棚卸表のスプレッドシートID';
name = 'シート1';
const comparedValues = SpreadsheetDataConverterToObject.getElementsArray(id, name);
const joinedCmpValues = comparedValues.map(element => [[element['商品ID'], element['賞味期限'], element['納品書番号']].join(``)]);
const joinedOrgValues = originalValues.map(element => [[element['商品ID'], element['賞味期限'], element['納品書番号']].join(``)]);
const cmpValues = joinedCmpValues.flat();
const orgValues = joinedOrgValues.flat();
const cmpDiffs = cmpValues.filter(element => orgValues.indexOf(element) === -1);
console.log(cmpDiffs);
const orgDiffs = orgValues.filter(element => cmpValues.indexOf(element) === -1);
console.log(orgDiffs);
}
しかしながら、このコードは使いまわしができそうですし、できればマジックナンバーとなっている[カラム名]の指定などはできるだけ汎用性をもたせたコードにしたいところです。欲を言えば誰でも使えるようにライブラリ化してしまいましょう。
まとめ
さて、今回は「テーブルを連想配列で取得する」についてお届けしました。連想配列で取得したデータがあまりに操作性が長けたので、ついでに突合作業も終わってしまいました💦.filter()メソッドって便利ですね。
さて、次回は最終回として、このコードをパーツ化(ライブラリ化)したいと思います。