LoginSignup
5
7

More than 3 years have passed since last update.

Array<object>→CSV→ダウンロードをJavaScriptで

Last updated at Posted at 2019-12-05

こちらの記事で作った管理画面につけたCSVダウンロードボタンの実装方法についての覚え書きです。
JavaScriptでCSV変換・読み込みを行うライブラリは複数ありますが、カスタマイズ性を考えフルスクラッチで書いてみます。

{ id: 1, name: "Mary", words: ["foo", "bar", "baz"] }

このように単純なkey-valueを持ったオブジェクトの配列を、以下のようにヘッダー行を持ったCSVに変換します。

id,name,words
1,"Mary","["foo","bar","baz"]"
.
.
.
arrayToCsv.js
/**
 * 単純なオブジェクトの配列をCSV文字列に変換
 * @param {Array<object>} array
 * @param {Array<string>} keyArray
 * @returns {string}
 */
export default (array, keyArray = []) => {
  const keys = keyArray;
  array.forEach((data) => {
    Object.keys(data).forEach((key) => {
      if (keys.indexOf(key) === -1) {
        keys.push(key);
      }
    });
  });
  const lineArray = [keys.join(',')].concat(
    array.map((data) => keys.map((key) => {
      let valueString = '';
      if (typeof data[key] === 'number') {
        valueString = data[key];
      } else if (typeof data[key] === 'string') {
        valueString = `"${data[key]}"`;
      } else {
        valueString = `"${JSON.stringify(data[key]).replace(/"/g, '""')}"`;
      }
      return valueString;
    }).join(',')),
  );
  return lineArray.join('\r\n');
};

CSVの構造への変化のために、最初に全てのkeyを自動でリストアップしてから各行の値を入れていきます。
引数にデフォルトのkeyの配列を渡すことでkeyの順番を指定できるようにしました。

この関数は文字列を返すのみなので、文字列からファイルを作成してダウンロードするための関数も用意します。

downloadStringFile.js
/**
 * 文字列からファイルをダウンロード
 * @param {string} string
 * @param {string} fileName
 * @param {string} type
 * @param {boolean} insertTimestampToFilename
 */
export default (string, fileName, type, insertTimestampToFilename) => {
  const downLoadLink = document.createElement('a');
  let name = fileName;
  if (insertTimestampToFilename) {
    const nameArray = name.split('.');
    const timestamp = new Date().toLocaleString().replace(/[/ :]/g, '_');
    nameArray[0] = `${nameArray[0]}_${timestamp}`;
    name = nameArray.join('.');
  }
  downLoadLink.download = name;
  downLoadLink.href = URL.createObjectURL(new Blob([string], { type }));
  downLoadLink.dataset.downloadurl = [type, downLoadLink.download, downLoadLink.href].join(':');
  downLoadLink.click();
};

ブラウザ上でユーザーにダウンロードさせるためには、aタグのdownload属性を利用します。
insertTimestampToFilenameにtrueを渡すと、ファイル名にタイムスタンプが追加されます。

実際に使うときはこんな感じです。

const csvContent = arrayToCsv(docs.map((doc) => (doc.data())), ['id']);
downloadStringFile(csvContent, 'members.csv', 'text/csv', true);

ここでは、FirestoreのDocumentSnapshotの配列を単純なオブジェクトの配列に変換したものをarrayToCsvに渡し(idを行の先頭にする)、タイムスタンプをつけたファイル名でダウンロードさせています。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7