Posted at
kintoneDay 15

forEach, map, filterなどをつかってkintoneのrecords配列をもっと上手に扱う

More than 1 year has passed since last update.

kintone JavaScript APIでkintoneのレコード配列を操作するとき、大体下記のような感じになると思います。

for (var i = 0; i < records.length; i++) {

records[i]['フィールドコード']['value'] = 123;
}

これが最もベーシックだと思いますが、いくつか問題点があります。



  • iの宣言が面倒

  • データへアクセスするための記述量が長い(records[i]['フィールドコード']['value'])

  • 不等式を間違えたりして無限ループしてしまうなどのバグを起こしやすい

for以外にも配列を扱う機能がJavaScriptには実装されているので、

状況に応じて、forEach, filter, mapなどを使い分けていく方がスマートです。

実際にユースケースを見ながら使い方を見てみます。

(当記事はまだこれらの関数を使いこなせていない、使ったことがない方向けの内容です)

下記ページで実際に試すことのできる環境を用意しました。

結果はコンソールを開いて確認してください。

https://jsfiddle.net/emgujhxj/2/


サンプル

顧客管理アプリのレコードを想定します。下記フィールドがあります。

フィールドコード
フィールドタイプ
備考

会社名
文字列一行
顧客の名前が格納される

単価
数値
販売した製品の単価が格納される

ユーザー数
数値
製品を購入したユーザー数を格納される

小計
数値
購入額合計を格納するフィールド

たとえば、上記のようなデータが有った場合、下記のような操作が必要になることがあります。

これを例にforと比較しながら見ていきます。


  • 会社名一覧の取得

  • 小計が10,000円以上のレコードのみを求める

  • 小計を求める(消費税込)

  • 全ての小計の合計


forEach

単純にすべてのレコードのデータを参照したい場合はforEachを使うのが適しています。


Array.prototype.forEach()


例)会社名一覧の取得



  • forで記述した場合

for (var i = 0; i < records.length; i++) {

console.log(records[i]['会社名']['value']); // 結果表示
}


  • forEachで記述した場合

records.forEach(function(record){

console.log(record['会社名']['value']); // 結果表示
});

わざわざ、何行目かを意識せずとも、record変数にrecordsのデータが1つずつ入って繰り返し処理を行ってくれますので見通しもよく便利です。

今までforでやっていることは、大抵このように実装できるはずですので、まずforEachで実装できないか考えてみましょう。

ちなみに今何行目か、index変数にアクセスすることもできます。


  • index変数にアクセス

records.forEach(function(record, i){

console.log(i + '行目の製品名: ' + record['製品名']['value']);
});


filter

filterを使えば条件に一致した配列を取得できます。

例えば、売上n円以上のデータだけほしい、ということを簡単にかけます。


Array.prototype.filter()


例)小計が10,000円以上のレコードのみを求める



  • forで記述した場合

var results = [];

for (var i = 0; i < records.length; i++) {
if (records[i]['小計']['value'] > 10000) {
results.push(records[i]);
}
}
console.log(results); // 結果表示


  • filterで記述した場合

var results = records.filter(function(record){

return (record['小計']['value'] > 10000);
});
console.log(results); // 結果表示

if文を使わずとも任意のデータが取得できるので見た目もすっきりします。

実際には、この程度の条件であればkintone APIを呼ぶときに指定すればいいですが、もうちょっと複雑な条件を指定したいときには重宝します。


map

mapを使えば、配列全てに処理を行うことができます。(新しい配列が返却されます)

Array.prototype.map()


例)小計を求める(消費税込)



  • forで記述した場合

var results = [];

for(var i = 0; i < records.length; i++) {
results.push(records[i]['小計']['value'] = records[i]['単価']['value'] * records[i]['ユーザー数']['value'] * 1.08);
}


  • mapで記述した場合

var results = records.map(function(record){

record['小計']['value'] = record['単価']['value'] * record['ユーザー数']['value'] * 1.08;
return record;
});
console.log(results); // 結果出力

これもタイプ数は大分減らせることが出来ました。


records[i]...から始まらない分、短くてすみますし、バグを引き起こす可能性を低くすることができます。


実際には、小計を出す程度だと自動計算フォームを使えばいいですが、それではできない複雑な計算をする場合に使えます。


reduce

reduceを使うとrecords配列の全ての合計値などを求めることができます。

reduceは上記に挙げたものと比べると少しむずかしく見えるかもしれませんが、慣れてしまえば簡単にデータの合計値などを求めることができます。

reduceは左から右に配列を処理しますが、逆のreduceRightもあります。

Array.prototype.reduce()


例)全ての小計の合計を求める



  • forで記述した場合

var results = 0;

for(var i = 0; i < records.length; i++) {
results += records[i]['小計']['value'];
}
console.log(results); // 結果出力


  • reduceで記述した場合

var results = records.reduce(function(prev, record){

return prev + record['小計']['value'];
}, 0);
console.log(results); // 結果出力

タイプ数は殆ど変わりませんので違いがわかりにくいですが、やはりindex変数iを使わない分バグの確率は減ります。

forEachでも実装はできますが、こちらはresultsの初期化も不要ですし、reduce内で処理が完結するのでまとまりがあります。


例のように合計値を求めたり、records配列をloopしてデータを計算したいときは積極的につかっていきたい関数です。


まとめ

いかがでしょうか、forしか使ったことがない場合は是非使ってみて下さい。最初は少しむずかしいかもしれませんが、慣れてしまえばforには戻れません。


単純にforを使うよりもバグを起こす可能性を減らせるだけでなく、見通しもいいので可読性もあがります。

これらの関数は比較的最近実装されたもので、Internet Explorer 9以上にしか実装されていません。しかし、kintoneも同様にIE9以上しかサポートしていないので、問題はないと思います。積極的に利用しましょう。

詳しい使い方や詳細については是非調べてみてください。上記以外にも有用な関数がたくさんあります。


注意点



  • for...inループを使っている方もいるかもしれませんが、推奨しません。理由はこちらです。

  • 見やすさを優先してサンプルコードでは省いていますが、きちんとNumber()などを使ってIntegerにparseしたほうがいいです。