2
\$\begingroup\$

I built this code as part of a test project that was given to me by a company. They had given me a .csv file that contained over 9000 records and wanted me to build a program that would upload it to Firebase.

Firebase has limits on how much data can be uploaded at one time, so uploading a large .json file would not have been possible (I know this cause I tried).

Tried my luck with promises also- not sure if I did that right, but the program worked lol.

The code below works just fine, but I feel as though I could do better- perhaps make it cleaner? I was working with Typescript for the first time. So if anyone has any tips on this please let me know. Typescript and I are not friends.

Tell me your thoughts please!

#!/usr/bin/env node

import csv from 'csvtojson';
import program from 'commander';
import * as fs from 'fs';
import * as path from 'path';
import * as firebase from 'firebase';
import firebaseConfig from './config';
import { resolve, parse } from 'path';
const ShardingToCsv = require('sharding-to-csv').ShardingToCsv;
const filehound = require('filehound');

// Set up Arguments in Command Line
program
  .version('1.0.0')
  .option('-s, --src <path>', 'Path to .csv file')
  .parse(process.argv);

// Initialize Firebase Config
firebase.initializeApp(firebaseConfig);

// Set DB for Referenced to firebase database
const db = firebase.database();

// If No DB Connection- let me know.
if (!db) {
  console.log('No Database Detected');
}

// Because the .CSV file is to large to parse and upload, break it into 10 different pieces.
const shardFiles = () => {
  // Set a Variable for the source path that the user inputs in
  const srcPath = program.src;

  // If no source path is entered, give this error message
  if (!srcPath) {
    console.log('Please provide valid path to .csv File');
  }

  // a Promise!
  return new Promise((resolve, reject) => {
    console.log('starting sharding process....');
    // Shard Larger .csv Files to Smaller versions for Firebase upload
    var sharding = new ShardingToCsv(srcPath, {
      encoding: 'iso-8859-1',
      maxFileSize: 1000000,
    }).shard();
    sharding.on('error', (err: any) => console.log(err), reject);
    sharding.on('completed', () => {
      console.log('Done Sharding, not to be confused with sharting!');
      // resolve promise
      resolve(sharding);
    });
  });
};

const fromDir = async () => {
  // Await the sharding of the files
  await shardFiles();

  // Actions to create .json files for each shard.

  // variable for shard directory
  // Change this Directory per your application

  const dir = './utils';
  // Read Shard Directory
  const files: any = fs.readdirSync(dir);
  // Interate over the Files
  for (const file of files) {
    const rawData: any = file;
    try {
      // Parse .csv shards into json files using csvtojson
      await csv()
        .fromFile(`utils/${rawData}`)
        .then((data) => {
          fs.writeFile(
            `./utils/${file}.json`,
            JSON.stringify(data, null, 4),
            (err) => {
              if (err) {
                throw err;
              }
              console.log(`created json file with ${file} name`);
            }
          );
        });
    } catch (err) {
      console.log(err);
    }
  }
};

// New Function to upload to database
const uploadToDatabase = async () => {
  // await creation of .json files
  await fromDir();

  filehound
    .create()
    .paths('./utils')
    .ext('.json')
    .find((err: any, jsonFiles: any) => {
      if (err) {
        return console.log(err);
      }
      const readFile = jsonFiles.map((jsonFile: any) => {
        const dbItem = jsonFile;
        const item: any = fs.readFileSync(dbItem);
        const parsedItem = JSON.parse(item);
        // console.log(parsedItem);

        firebase.database().ref('funds').set({ parsedItem });
        console.log('uploaded to database!');
      });
    });
};

uploadToDatabase();
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Just a question: are you uploading and downloading it as complete files, or are you reading small branches as well?Firebase database is for reading and uploading small parts but reading/updating often. Firebase firestore is for uploading and downloading big chunks at a time. And finally firebase storage is for treating it entirely as a file. \$\endgroup\$ Commented Jun 26, 2020 at 18:58
  • 2
    \$\begingroup\$ I was uploading to a Firebase Realtime Database a .csv file with over 9000 records. When I parsed the .csv file to Json it was around 30mb. Firebase as a 10mb Limit, so this program essentially shards to file into around 10 .csv files- parsed those to JSON( around 3mb each) and then uploads the individual files to Firestore. \$\endgroup\$ Commented Jun 26, 2020 at 19:11
  • 1
    \$\begingroup\$ Thx, was just checking why you didn't go for the other options, but when you want to set something big up and then access individual records is a logical reason. I, unfortunately, am a beginner in typescript/javaScript, so I cannot help you... I'm sorry \$\endgroup\$ Commented Jun 26, 2020 at 19:35

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.