こちらの記事で作った管理画面につけたCSVダウンロードボタンの実装方法についての覚え書きです。
JavaScriptでCSV変換・読み込みを行うライブラリは複数ありますが、カスタマイズ性を考えフルスクラッチで書いてみます。
{ id: 1, name: "Mary", words: ["foo", "bar", "baz"] }
このように単純なkey-valueを持ったオブジェクトの配列を、以下のようにヘッダー行を持ったCSVに変換します。
id,name,words
1,"Mary","["foo","bar","baz"]"
.
.
.
/**
* 単純なオブジェクトの配列を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の順番を指定できるようにしました。
この関数は文字列を返すのみなので、文字列からファイルを作成してダウンロードするための関数も用意します。
/**
* 文字列からファイルをダウンロード
* @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
を行の先頭にする)、タイムスタンプをつけたファイル名でダウンロードさせています。