1

BEFORE ANYONE MARKS THIS AS DUPLICATE, I AM AWARE OF: How to import CSV or JSON to firebase cloud firestore

As in the question above, I am trying to send JSON to Firestore using a Google Cloud Function, allowing me to convert my realtime database to Firestore. I have been using the script provided as an answer by Maciej Kaputa in the link above. The script he provides is as follows, which is exactly the same as that provided in the link above:

const admin = require('../functions/node_modules/firebase-admin');
const serviceAccount = require("./service-key.json");

admin.initializeApp({
 credential: admin.credential.cert(serviceAccount),
 databaseURL: "https://<your-database-name>.firebaseio.com"
});

const data = require("./fakedb.json");

/**
* Data is a collection if
*  - it has a odd depth
*  - contains only objects or contains no objects.
*/
function isCollection(data, path, depth) {
 if (
  typeof data != 'object' ||
  data == null ||
  data.length === 0 ||
  isEmpty(data)
 ) {
return false;
}

for (const key in data) {
 if (typeof data[key] != 'object' || data[key] == null) {
    // If there is at least one non-object item then it data then it cannot be   collection.
  return false;
 }
}

  return true;
}

// Checks if object is empty.
function isEmpty(obj) {
  for(const key in obj) {
    if(obj.hasOwnProperty(key)) {
  return false;
   }
}
 return true;
}

async function upload(data, path) {
 return await admin.firestore()
   .doc(path.join('/'))
  .set(data)
  .then(() => console.log(`Document ${path.join('/')} uploaded.`))
  .catch(() => console.error(`Could not write document ${path.join('/')}.`));
 }

 /**
*
*/
 async function resolve(data, path = []) {
 if (path.length > 0 && path.length % 2 == 0) {
    // Document's length of path is always even, however, one of keys can actually be a collection.

    // Copy an object.
const documentData = Object.assign({}, data);

    for (const key in data) {
     // Resolve each collection and remove it from document data.
  if (isCollection(data[key], [...path, key])) {
      // Remove a collection from the document data.
    delete documentData[key];
      // Resolve a colleciton.
    resolve(data[key], [...path, key]);
    }
  }

  // If document is empty then it means it only consisted of collections.
  if (!isEmpty(documentData)) {
    // Upload a document free of collections.
    await upload(documentData, path);
   }
  } else {
   // Collection's length of is always odd.
   for (const key in data) {
  // Resolve each collection.
     await resolve(data[key], [...path, key]);
   }
  }
   }

resolve(data);

However, this does not seem to work for me. I have set up my firebase cli in the usual way and checked if functions can be sent to my project by running the standard "Hello world" function with success. It is not a problem with my JSON, as I have used an online validator. Through some research, I found that eslint ecmaVersion 6 does not allow async functions, which can be resolved by changing the ecmaVersion in the .eslintrc.json file to "ecmaVersion": 2017. Next, you have to delete some rules from the .eslintrc.json, these are // Require the use of === and !==, // Disallow null comparisons without type-checking operators and // Disallow await inside of loops. Now, with these modifications, when I type firebase deploy --only functions into my functions folder in the terminal, I am told that the function was deployed and provided with a link to my Firebase console. However, my function doesn't appear in the functions tab of firebase, nor is my data uploaded to the cloud firestore. Does anyone know what i am doing wrong? Could it be that I am not calling exports on the function? Or is this used only for prebuilt Firebase functions?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
pho_pho
  • 672
  • 11
  • 30
  • What is this this fakedb.json? is it a constant name for the exported json and where is it stored? in the local machine? – Sony Mar 03 '18 at 17:43
  • Can you share your data migration project? – Sony Mar 03 '18 at 18:01
  • 1
    Hi @Sony, this is your JSON file that you want to upload to Firestore. Before you run the script, copy and paste your JSON into an online validator (such as https://jsonlint.com) to ensure that it is valid. The file itself should be located in the same folder as the script. The `./fakedb.json` is the file location, where the '.' essentially indicates that it is in the current folder. You need to download your service key from Firebase, you can find instructions on how to do this here: https://hackernoon.com/filling-cloud-firestore-with-data-3f67d26bd66e, under "Authentication". – pho_pho Mar 03 '18 at 19:08
  • I got that working, Thanks for your time :-) – Sony Mar 03 '18 at 19:16

1 Answers1

4

That script is not a Cloud Function, it looks like it is desired to simply run as a Node.js standalone script with data been given whatever data from RTDB you want in Cloud Firestore.

If you want to use it as a Cloud Function, you'll need to set some exports and use the data from them as the value of data. Note - that will only allow you to transfer the data changed/read. You'll likely want to run this against the entire DB at least a first (hence why it's a standalone script).

Dan McGrath
  • 41,220
  • 11
  • 99
  • 130
  • You sir, are an absolute genius! Thank you so much for taking the time to help! For anyone else interested in getting this script to work, I ran it by entering `node index.js` in the terminal. Thank you very much Dan! – pho_pho Mar 03 '18 at 14:51