Is there a way to import CSV or JSON to firebase cloud firestore like in firebase realtime database?
Note: Cloud Firestore supports a variety of data types for values: boolean, number, string, geo point, binary blob, and timestamp. You can also use arrays or nested objects, called maps, to structure data within a document. You may notice that documents look a lot like JSON. In fact, they basically are.
General Solution
I've found many takes on a script allowing to upload a JSON but none of them allowed sub-collections. My script above handles any level of nesting and sub-collections. It also handles the case where a document has its own data and sub-collections. This is based on the assumption that collection is array/object of objects (including an empty object or array).
To run the script make sure you have npm and node installed. Then run your code as node <name of the file>
. Note, there is no need to deploy it as a cloud funciton.
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 in the 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);
You need a custom script to do that.
I wrote one based on the Firebase admin SDK, as long as firebase library does not allow you to import nested arrays of data.
const admin = require('./node_modules/firebase-admin'); const serviceAccount = require("./service-key.json"); const data = require("./data.json"); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: "https://YOUR_DB.firebaseio.com" }); data && Object.keys(data).forEach(key => { const nestedContent = data[key]; if (typeof nestedContent === "object") { Object.keys(nestedContent).forEach(docTitle => { admin.firestore() .collection(key) .doc(docTitle) .set(nestedContent[docTitle]) .then((res) => { console.log("Document successfully written!"); }) .catch((error) => { console.error("Error writing document: ", error); }); }); } });
Update: I wrote an article on this topic - Filling Firestore with data
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With