Is there a way to import CSV or JSON to firebase cloud firestore like in firebase realtime database?
-
1See my post for a general solution, handling sub-colleciotions too. – Maciej Caputa Nov 26 '17 at 00:00
13 Answers
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);

- 1,112
- 4
- 16
- 34

- 1,831
- 12
- 20
-
2This worked great for me, this is a much better (robust and general) solution than one of Mikki. Use this one – the setup is the same btw so you try either this one or the one from Mikki very easily – just replacing the actual code. – inteist Nov 30 '17 at 23:06
-
1@Maciej Caputa, Your solution works great. Thanks. However can you suggest how would you modify the fakedb.json so that it generates auto Id, rather than sequence - 1, 2, 3, ... – Rinav Jan 05 '18 at 14:17
-
1@Rinav You can have an array treated either as a collection with auto ID or a sequence 0,1,2,3... It all depends on the structure of your JSON file. It all comes down to the fact that array on a property with an even number of items in a path will be treated as sequence and if odd it will be treated as a collection. I have implemented this way but note that this is actually only compliant way with Firebase specification. I wonder when Firebase will implement this in firebase tools. – Maciej Caputa Jan 06 '18 at 14:39
-
-
Would it be possible for anyone to please elaborate on how to use this script for beginners please... 1) I have copied it into my index.js file 2) downloaded the admin service key and saved it on my desktop, then replaced ""./service-key.json" in the service account constant with its file location 3) filled in the
with mine 4) replaced "./fakedb.json" with the path to the json file that I would like uploaded. Am I missing anything? I noticed that this ->> '../functions/node_modules/firebase-admin' starts with two periods, is that correct or a typo? – pho_pho Mar 02 '18 at 00:09 -
1You need to ensure that you have node and npm installed. Then you need to install firebase-admin and its dependencies. The path that you refer to has no typo in it, it is a reference to the package in the node module that is required by this solution. You should replace it with your own, however, this one assumes that in your folder structure you have a folder for uploading the data next to the functions one. – Maciej Caputa Mar 02 '18 at 11:27
-
I am receiving the error "14:20 error Parsing error: Unexpected token : ", which I suppose indicates that there is an error in your script such that the JSON is not being parsed to the firestorm data structure? – pho_pho Mar 02 '18 at 16:15
-
1That most likely means that your JSON file is not correct, you can use online validators to make sure it is correctly formatted. – Maciej Caputa Mar 02 '18 at 16:18
-
Thanks for the script Maciej, I was trying to deploy it using the firebase CLI (`firebase deploy --only functions`). I found that instead you run it using `node index.js` and it works perfectly. – pho_pho Mar 03 '18 at 14:54
-
2Happy to help.I added a note to my answer for further reference. – Maciej Caputa Mar 03 '18 at 19:40
-
4It would be great if you could also provide an example of the JSON structure to use to feed the database. I ran the script and it created a separate collection for each block of data and each character in the fields came up as a separate field. Now I have a big mess to clean up and there is no bulk delete function... – pasx Jun 06 '18 at 10:20
-
I am getting this error >> Auth error:Error: invalid_grant: Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values and use a clock with skew to account for clock differences between systems. – Umer Jul 22 '18 at 08:01
-
seems that API has been changed: getting a bunch of 'UnhandledPromiseRejectionWarning'. Fixed by replacing 'firebase-admin' module with 'firebase' – divideByZero Jan 14 '19 at 02:22
-
How do I get subcollections working in this? I tried a json file with `"title": {"id":1}` but that only creates a map. – Carrein Jan 23 '19 at 11:54
-
2Here is an example of subcollection: { "testCollection": { "testDocument": { "testNestedCollection": { "testNestedDocument": { "nestedName": "Jack" } }, "name": "John" } } }. Before using the script you should use a JSON linter such as https://jsonlint.com to ensure your syntax is correct. – michael-martinez Feb 24 '19 at 15:28
-
Here are additional advices for NodeJS beginners: `npm -v && node -v && npm init` (this will create the configuration file, default options should be fine). Then replace `../functions/` with `./` if your node_nodules/ folder is in your working directory. Then grab the admin keys from the https://console.firebase.google.com/u/0/project/
/settings/serviceaccounts/adminsdk webpage and you are good to go. – michael-martinez Feb 24 '19 at 15:40
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

- 7,479
- 5
- 34
- 49
-
1The link at the bottom was very helpful, and gave a lot of context which made this answer make a lot more sense. – firecape Nov 08 '18 at 04:00
-
1Thanks for the example and the article. This solution worked perfectly for me and helped explain how to do things on the backend that someone new to Vue.js really appreciates! – akaHeimdall Dec 19 '18 at 20:15
-
1
-
1Your article made using any of these node scripts on this page possible for me. Setting up that service in Firebase is crucial. – KhanKhuu Mar 20 '20 at 20:05
-
1
-
There is not, you'll need to write your own script at this time.

- 41,220
- 11
- 99
- 130
-
-
4I love how Firebase goes to great lengths on stackoverflow to see what developers need, but it'd be great if these efforts eventually lead to features being added. I'd say JSON/CSV upload would tremendous :) – Dan Sabin Jan 13 '19 at 00:23
I used the General Solution provided by Maciej Caputa. Thank you (:
Here are a few hints. Assuming that you have an Ionic Firebase application installed with the required Firebase node modules in the functions folder inside that solution. This is a standard Ionic Firebase install. I created an import folder to hold the script and data at the same level.
Folder Hierarchy
myIonicApp
functions
node_modules
firebase-admin
ImportFolder
script.js
FirebaseIonicTest-a1b2c3d4e5.json
fileToImport.json
Script Parameters
const admin = require('../myIonicApp/functions/node_modules/firebase-admin'); //path to firebase-admin module
const serviceAccount = require("./FirebaseTest-xxxxxxxxxx.json"); //service account key file
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://fir-test-xxxxxx.firebaseio.com" //Your domain from the hosting tab
});
Creating the Service Account Key File
- In the Firebase console for your project, next to the Project Overwiew item, click on the gear icon and select Users and permissions
- At the bottom of the screen, click Advanced permission settings
- This opens another tab for the Google Cloud Platform Console
- On the left select the Service Accounts item
- Create a Service Account for an existing Service Account
I simply added a key to the App Engine default service account
The Create key function will offer to download the key to a JSON file
JSON Data Structure
To use the script provided, the data structure must be as follows:
{
"myCollection" : {
"UniqueKey1" : {
"field1" : "foo",
"field2" : "bar"
},{
"UniqueKey2" : {
"field1" : "fog",
"field2" : "buzz"
}...
}

- 2,718
- 1
- 34
- 26
-
This and Mikki's article helped me to get Maciej's script working. It would be nice for posterity if Maciej put it all together in his answer. There is one error in your example JSON here, although without it I was having issues with arrays behaving differently than I expected. The error is in the line that looks like },{. that extra { needs to be gone unless we are trying to make a subcollection. – KhanKhuu Mar 20 '20 at 20:03
For reference. I wrote a function that helps to import and export data in Firestore.
https://github.com/dalenguyen/firestore-import-export (archived)
Updated 2023:
Use this package instead. Thanks, @Webber

- 1,930
- 3
- 24
- 37
-
-
2
-
1Note that the package is no longer maintained and now refers to a maintained package: https://github.com/dalenguyen/firestore-backup-restore – Webber Jan 15 '23 at 19:22
https://gist.github.com/JoeRoddy/1c706b77ca676bfc0983880f6e9aa8c8
This should work for an object of objects (generally how old firebase json is set up). You can add that code to an app that's already configured with Firestore.
Just make sure you have it pointing to the correct JSON file.
Good luck!

- 729
- 6
- 12
This workaround in Python may help some people. First convert json or csv to dataframe using Pandas, then convert dataframe to dictionary and upload dictionary to firestore.
import firebase_admin as fb
from firebase_admin import firestore
import pandas as pd
cred = fb.credentials.Certificate('my_credentials_certificate.json')
default_app = fb.initialize_app(cred)
db = firestore.client()
df = pd.read_csv('data.csv')
dict = df.to_dict(orient='records')
my_doc_ref = db.collection('my_collection').document('my_document')
my_doc_ref.set(dict)
There could be similar workarounds in javascript and other languages using libraries similar to Pandas.

- 1,088
- 14
- 22
No as of now, you can't.. firestore structures data into a different format that is, using collections and each collection has a series of documents which then are stored in JSON format.. in future they might make a tool to convert JSON in to firestore.. for reference check this out
:https://cloud.google.com/firestore/docs/concepts/structure-data
****EDIT :****
You can automate the process up to some extent, that is, write a mock software which only pushes the fields of your CSV or JSON data into your Cloud Firestore DB. I migrated my whole database my making just a simple app which retrieved my DB and pushed it on Firestore

- 242
- 7
- 13
var admin = require('firebase-admin');
var serviceAccount = require('./serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://csvread-d149c.firebaseio.com'
});
const csv = require('csv-parser');
const fs = require('fs');
const firestore = admin.firestore();
// CSV FILE data.csv
// Name,Surname,Age,Gender
// John,Snow,26,M
// Clair,White,33,F
// Fancy,Brown,78,F
fs.createReadStream('data.csv')
.pipe(csv())
.on('data', (row) => {
console.log(row);
if(row) {
firestore.collection('csv').add({
name: row.Name,
surname: row.Surname,
age: row.Age,
sex: row.Gender
});
}
else {
console.log('No data')
}
})
.on('end', () => {
console.log('CSV file successfully processed');
});

- 41
- 4
There is now a paid GUI tool that does this, Firefoo. I haven't used it, but it seems quite powerful for managing Firestore - including importing csv files:

- 129
- 5
This is a small modification that copies the 'id' of the document, if exists, to its path. Otherwise it will use the "for"'s index.
...
...
} else {
// Collection's length of is always odd.
for (const key in data) {
// Resolve each collection.
if (data[key]['id']!==undefined)
await resolve(data[key], [...path,data[key]['id']])
else
await resolve(data[key], [...path, key]);
}
}
}
resolve(data);

- 3
- 2
1 - Importing only collections
If the names of your collections are not only composed of numbers, then you can define the name of the document as follows.
...
...
} else {
// Collection's length of is always odd.
for (const key in data) {
// // Resolve each collection.
// If key is a number it means that it is not a collection
// The variable id in this case will be the name of the document field or you
// can generate randomly
let id = !isNaN(key) ? data[key].id : key;
await resolve(data[key], [...path, id]);
}
}
}
2 - Import collections and sub-collections
In the same way as in the example above, the name of the sub-collection can not contain only numbers.
...
...
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];
// If key is a number it means that it is not a collection
// The variable id in this case will be the name of the document field or you
// can generate randomly
let id = !isNaN(key) ? data[key].id : key;
// Resolve a colleciton.
resolve(data[key], [...path, id]);
}
}
...
...
Note.: Changes in @Maciej Caputa's code

- 21
- 2
this library you can use https://www.npmjs.com/package/csv-to-firestore
install this library with this command npm i -g csv-to-firestore
put this script inside your ./scripts
module.exports = {
path: "./scripts/palabrasOutput.csv",
firebase: {
credential: "./scripts/serviceAccount.json",
collection: "collectionInFirestore",
},
mapper: (dataFromCSV) => {
return dataFromCSV;
},
};
and run:
csv-to-firestore --config ./scripts/csvToFirestore.js
btw: Generate new private key (it's a file in Service account section in firestore) put that file in /scripts folder and rename serviceAccount.json

- 1,386
- 7
- 13