Last active
September 27, 2019 23:23
-
-
Save voscausa/cb64e7245a5c8b7a14bee60411f16e23 to your computer and use it in GitHub Desktop.
Batch upload a CSV file in a Firestore collection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
// other imports | |
import Upload from "./upload/Upload.svelte"; | |
// auth stuff | |
export let uid; | |
// use a dynamic component to be able to stop the component | |
let upload_component = Upload; | |
// we restart the component after the upload to clear the filename of the <input type="file" ..../> | |
let restart = false; | |
$: if (restart) { | |
// use a falsy to stop / destroy this component | |
upload_component = null; | |
// use a timer to queue a restart after the componets has stopped | |
setTimeout(() => { | |
console.log('Upload component restarts') | |
upload_component = Upload | |
}, 0); | |
console.log('Upload component restart queued'); | |
restart = false; | |
}; | |
</script> | |
<style> | |
input { | |
display: block; | |
} | |
</style> | |
<!-- dynamic Upload component to restart the component when finished--> | |
<svelte:component uid={uid} this={upload_component} bind:finished={restart}/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { db } from "./../firebase"; | |
let uid; | |
let callback; | |
const MATCHSEP = new RegExp(/[^\r\n]+/gu); // split line | |
// const UNQUOTE = new RegExp(/^(").*(")$/gu); // remove start and end quotes | |
function batchRows(collectionName, batch) { | |
const idLen = 4; | |
const colNames = []; | |
let rowId = 0; | |
return (csvRow, rowNum) => { | |
const csvRowObj = {}; | |
const rowItems = csvRow.split(';'); | |
if (rowNum === 0) { | |
// get the colNames from the first csvRow | |
colNames.push(...rowItems); | |
} else { | |
// and the values from the other csvRows | |
for (const [i, v] of rowItems.entries()) { | |
csvRowObj[colNames[i]] = v; | |
} | |
if (!('id' in colNames)) { | |
// no id: use a fixed length numeric id with leading spaces | |
csvRowObj.id = (' '.repeat(idLen) + rowId).slice(-idLen); | |
rowId++; | |
} | |
// set an csvRow object in the uploads collection | |
let ref = db.collection(collectionName).doc(csvRowObj.id); | |
batch.set(ref, { | |
uid, created: Date.now(), ...csvRowObj | |
}); | |
} | |
} | |
} | |
function fileSelect(event) { | |
//handle file select and create a batch of CSV rows to update the collection | |
const reader = new FileReader() | |
let files = event.target.files; | |
let f = files[0]; | |
const collectionName = f.name; | |
reader.onload = (e) => { | |
const batch = db.batch(); | |
const _batchRows = batchRows(collectionName, batch); | |
let contents = e.target.result; | |
let csvRows = contents.match(MATCHSEP); | |
csvRows.forEach(_batchRows); | |
batch.commit().then(() => { | |
console.log(`Batch for : ${collectionName} committed`); | |
callback(`Upload : ${collectionName} OK, CSV length : ${csvRows.length} rows`); | |
}); | |
}; | |
reader.onerror = (e) => { | |
callback(`Upload : ${collectionName} error: ${e.target.error.code}`); | |
}; | |
if (f.type.match('application/vnd.ms-excel')) { | |
reader.readAsText(f); | |
} else { | |
callback(`Upload : ${collectionName} Invalid type: ${f.type} Must be a CSV file`) | |
} | |
} | |
export function uploadCsv(args) { | |
uid, callback = [...args]; | |
return fileSelect; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import { onDestroy } from 'svelte'; | |
import { uploadCsv } from './upload.js' | |
export let uid = null; | |
export let finished; | |
function uploadCsvCallback(result) { | |
console.log(result); | |
// restart is bound to component | |
finished = true; | |
}; | |
onDestroy(() => { | |
console.log('Upload component destroyed'); | |
}); | |
</script> | |
<style> | |
.float-right { | |
float: right; | |
} | |
</style> | |
<input type="file" name="files" class="float-right" accept=".csv" | |
on:change={uploadCsv(uid, uploadCsvCallback)}/> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment