firestore-export-import
Advanced tools
Comparing version 0.3.3 to 0.3.4
@@ -14,3 +14,3 @@ # Change log | ||
## [0.3.3] - 2020-01-03 | ||
## [0.3.4] - 2020-03-17 | ||
@@ -20,2 +20,14 @@ #### - :nail_care: [Polish] | ||
- Update new packages | ||
- Fixed security package: minimist | ||
#### - :rocket: [New Feature] | ||
- Supported import array of references | ||
- Supported multi sub collections | ||
## [0.3.3] - 2020-03-10 | ||
#### - :nail_care: [Polish] | ||
- Update new packages | ||
- Check app before initializing | ||
@@ -22,0 +34,0 @@ |
@@ -14,11 +14,13 @@ "use strict";var __awaiter=(this&&this.__awaiter)||function(thisArg,_arguments,P,generator){function adopt(value){return value instanceof P?value:new P(function(resolve){resolve(value);});} | ||
else | ||
return acc[cur]||{};},documentObj);});};exports.restore=function(fileName,options){var db=admin.firestore();return new Promise(function(resolve,reject){if(typeof fileName==='object'){var dataArray=fileName;updateCollection(db,dataArray,options).then(function(){resolve({status:true,message:'Collection successfully imported!'});}).catch(function(error){reject({status:false,message:error.message});});} | ||
return acc[cur]||{};},documentObj);});};exports.restore=function(fileName,options){var db=admin.firestore();return new Promise(function(resolve,reject){if(typeof fileName==='object'){var dataObj=fileName;updateCollection(db,dataObj,options).then(function(){resolve({status:true,message:'Collection successfully imported!'});}).catch(function(error){reject({status:false,message:error.message});});} | ||
else{fs.readFile(fileName,'utf8',function(err,data){if(err){console.log(err);reject({status:false,message:err.message});} | ||
var dataArray=JSON.parse(data);updateCollection(db,dataArray,options).then(function(){resolve({status:true,message:'Collection successfully imported!'});}).catch(function(error){reject({status:false,message:error.message});});});}}).catch(function(error){return console.error(error);});};var updateCollection=function(db,dataArray,options){if(options===void 0){options={};} | ||
return __awaiter(void 0,void 0,void 0,function(){var _a,_b,_i,index,collectionName,_c,_d,_e,doc,docId,subCollections;return __generator(this,function(_f){switch(_f.label){case 0:_a=[];for(_b in dataArray) | ||
_a.push(_b);_i=0;_f.label=1;case 1:if(!(_i<_a.length))return[3,9];index=_a[_i];collectionName=index;_c=[];for(_d in dataArray[index]) | ||
_c.push(_d);_e=0;_f.label=2;case 2:if(!(_e<_c.length))return[3,8];doc=_c[_e];if(!dataArray[index].hasOwnProperty(doc))return[3,7];docId=Array.isArray(dataArray[index])?uuid_1.v1():doc;if(!dataArray[index][doc]['subCollection'])return[3,5];subCollections=dataArray[index][docId]['subCollection'];delete dataArray[index][doc]['subCollection'];return[4,startUpdating(db,collectionName,docId,dataArray[index][doc],options)];case 3:_f.sent();return[4,updateCollection(db,subCollections)];case 4:_f.sent();return[3,7];case 5:return[4,startUpdating(db,collectionName,docId,dataArray[index][doc],options)];case 6:_f.sent();_f.label=7;case 7:_e++;return[3,2];case 8:_i++;return[3,1];case 9:return[2];}});});};var startUpdating=function(db,collectionName,docId,data,options){if(options.dates&&options.dates.length>0){updateTime(options.dates,data);} | ||
if(options.refs&&options.refs.length>0){options.refs.forEach(function(ref){if(data.hasOwnProperty(ref)){data[ref]=db.doc(data[ref]);}});} | ||
var dataObj=JSON.parse(data);updateCollection(db,dataObj,options).then(function(){resolve({status:true,message:'Collection successfully imported!'});}).catch(function(error){reject({status:false,message:error.message});});});}}).catch(function(error){return console.error(error);});};var updateCollection=function(db,dataObj,options){if(options===void 0){options={};} | ||
return __awaiter(void 0,void 0,void 0,function(){var _a,_b,_i,index,collectionName,_c,_d,_e,doc,docId,subCollections,subCollections,_f,_g,_h,subIndex,revivedSubCollection,subCollectionPath;return __generator(this,function(_j){switch(_j.label){case 0:_a=[];for(_b in dataObj) | ||
_a.push(_b);_i=0;_j.label=1;case 1:if(!(_i<_a.length))return[3,13];index=_a[_i];collectionName=index;_c=[];for(_d in dataObj[index]) | ||
_c.push(_d);_e=0;_j.label=2;case 2:if(!(_e<_c.length))return[3,12];doc=_c[_e];if(!dataObj[index].hasOwnProperty(doc))return[3,11];docId=Array.isArray(dataObj[index])?uuid_1.v1():doc;if(!!Array.isArray(dataObj[index]))return[3,6];subCollections=dataObj[index][docId]['subCollection'];delete dataObj[index][doc]['subCollection'];return[4,startUpdating(db,collectionName,docId,dataObj[index][doc],options)];case 3:_j.sent();if(!subCollections)return[3,5];return[4,updateCollection(db,subCollections,options)];case 4:_j.sent();_j.label=5;case 5:return[3,11];case 6:subCollections=dataObj[index][doc]['subCollection'];delete dataObj[index][doc]['subCollection'];return[4,startUpdating(db,collectionName,docId,dataObj[index][doc],options)];case 7:_j.sent();if(!subCollections)return[3,11];_f=[];for(_g in subCollections) | ||
_f.push(_g);_h=0;_j.label=8;case 8:if(!(_h<_f.length))return[3,11];subIndex=_f[_h];revivedSubCollection={};subCollectionPath=collectionName+"/"+docId+"/"+subIndex;revivedSubCollection[subCollectionPath]=subCollections[subIndex];return[4,updateCollection(db,revivedSubCollection,options)];case 9:_j.sent();_j.label=10;case 10:_h++;return[3,8];case 11:_e++;return[3,2];case 12:_i++;return[3,1];case 13:return[2];}});});};var startUpdating=function(db,collectionName,docId,data,options){if(options.dates&&options.dates.length>0){updateTime(options.dates,data);} | ||
if(options.refs&&options.refs.length>0){options.refs.forEach(function(ref){if(data.hasOwnProperty(ref)){if(Array.isArray(data[ref])){data[ref]=data[ref].map(function(ref){return db.doc(ref);});} | ||
else{data[ref]=db.doc(data[ref]);}}});} | ||
if(options.geos&&options.geos.length>0){options.geos.forEach(function(geo){if(data.hasOwnProperty(geo)){data[geo]=new admin.firestore.GeoPoint(data[geo]._latitude,data[geo]._longitude);} | ||
else{console.warn('Please check your geo parameters!!!',options.geos);}});} | ||
return new Promise(function(resolve,reject){db.collection(collectionName).doc(docId).set(data).then(function(){console.log(docId+" was successfully added to firestore!");resolve({status:true,message:docId+" was successfully added to firestore!"});}).catch(function(error){console.log(error);reject({status:false,message:error.message});});});}; |
{ | ||
"name": "firestore-export-import", | ||
"version": "0.3.3", | ||
"version": "0.3.4", | ||
"description": "NPM package for backup and restore Firebase Firestore", | ||
@@ -31,7 +31,8 @@ "main": "dist/index.js", | ||
"devDependencies": { | ||
"@types/chai": "^4.2.10", | ||
"@types/chai": "^4.2.11", | ||
"@types/mocha": "^7.0.2", | ||
"@types/node": "^13.9.0", | ||
"@types/node": "^13.9.1", | ||
"chai": "^4.2.0", | ||
"jsmin": "^1.0.1", | ||
"minimist": "^1.2.5", | ||
"mocha": "^7.1.0", | ||
@@ -44,4 +45,7 @@ "request": "^2.88.2", | ||
"dependencies": { | ||
"firebase-admin": "^8.9.2" | ||
"firebase-admin": "^8.10.0" | ||
}, | ||
"resolutions": { | ||
"minimist": "1.2.5" | ||
}, | ||
"engines": { | ||
@@ -48,0 +52,0 @@ "node": ">=7.6.0" |
@@ -38,7 +38,7 @@ # firestore-export-import | ||
const firestoreService = require('firestore-export-import'); | ||
const serviceAccount = require('./serviceAccountKey.json'); | ||
const firestoreService = require('firestore-export-import') | ||
const serviceAccount = require('./serviceAccountKey.json') | ||
// Initiate Firebase App | ||
firestoreService.initializeApp(serviceAccount, databaseURL); | ||
firestoreService.initializeApp(serviceAccount, databaseURL) | ||
@@ -48,3 +48,3 @@ // Start exporting your data | ||
.backup('collection-name') | ||
.then(data => console.log(JSON.stringify(data))); | ||
.then(data => console.log(JSON.stringify(data))) | ||
``` | ||
@@ -67,4 +67,4 @@ | ||
// You can do whatever you want with collections | ||
console.log(JSON.stringify(collections)); | ||
}); | ||
console.log(JSON.stringify(collections)) | ||
}) | ||
``` | ||
@@ -97,3 +97,3 @@ | ||
refs: ['refKey'] | ||
}; | ||
} | ||
``` | ||
@@ -106,15 +106,15 @@ | ||
const firestoreService = require('firestore-export-import'); | ||
const serviceAccount = require('./serviceAccountKey.json'); | ||
const firestoreService = require('firestore-export-import') | ||
const serviceAccount = require('./serviceAccountKey.json') | ||
// Initiate Firebase App | ||
firestoreService.initializeApp(serviceAccount, databaseURL); | ||
firestoreService.initializeApp(serviceAccount, databaseURL) | ||
// Start importing your data | ||
// The array of date and location fields are optional | ||
// The array of date, location and reference fields are optional | ||
firestoreService.restore('your-file-path.json', { | ||
dates: ['date1', 'date1.date2', 'date1.date2.date3'], | ||
geos: ['location1', 'location2'], | ||
refs: ['refKey'] | ||
}); | ||
refs: ['refKey', 'arrayRef'] | ||
}) | ||
``` | ||
@@ -169,2 +169,3 @@ | ||
"secondRef": "test/second-key", | ||
"arrayRef": ["test/second-key", "test/second-key"], | ||
"subCollection": { | ||
@@ -213,3 +214,15 @@ "test/first-key/details": { | ||
"name": "Dale Nguyen", | ||
"email": "dale@dalenguyen.me" | ||
"email": "dale@dalenguyen.me", | ||
"subCollection": { | ||
"details": [ | ||
{ | ||
"dogId": "2", | ||
"dogName": "hello" | ||
}, | ||
{ | ||
"dogName": "lala", | ||
"dogId": "2" | ||
} | ||
] | ||
} | ||
}, | ||
@@ -216,0 +229,0 @@ { |
@@ -1,9 +0,9 @@ | ||
import * as fs from 'fs'; | ||
import { v1 as uuidv1 } from 'uuid'; | ||
import * as admin from 'firebase-admin'; | ||
import * as fs from 'fs' | ||
import { v1 as uuidv1 } from 'uuid' | ||
import * as admin from 'firebase-admin' | ||
export interface IImportOptions { | ||
dates?: string[]; | ||
geos?: string[]; | ||
refs?: string[]; | ||
dates?: string[] | ||
geos?: string[] | ||
refs?: string[] | ||
} | ||
@@ -20,7 +20,7 @@ | ||
if (!a[i + 1] && acc[cur] && acc[cur]._seconds) { | ||
acc[cur] = new Date(acc[cur]._seconds * 1000); | ||
} else return acc[cur] || {}; | ||
}, documentObj); | ||
}); | ||
}; | ||
acc[cur] = new Date(acc[cur]._seconds * 1000) | ||
} else return acc[cur] || {} | ||
}, documentObj) | ||
}) | ||
} | ||
@@ -37,9 +37,9 @@ /** | ||
): Promise<any> => { | ||
const db = admin.firestore(); | ||
const db = admin.firestore() | ||
return new Promise((resolve, reject) => { | ||
if (typeof fileName === 'object') { | ||
let dataArray = fileName; | ||
let dataObj = fileName | ||
updateCollection(db, dataArray, options) | ||
updateCollection(db, dataObj, options) | ||
.then(() => { | ||
@@ -49,18 +49,18 @@ resolve({ | ||
message: 'Collection successfully imported!' | ||
}); | ||
}) | ||
}) | ||
.catch(error => { | ||
reject({ status: false, message: error.message }); | ||
}); | ||
reject({ status: false, message: error.message }) | ||
}) | ||
} else { | ||
fs.readFile(fileName, 'utf8', function(err, data) { | ||
if (err) { | ||
console.log(err); | ||
reject({ status: false, message: err.message }); | ||
console.log(err) | ||
reject({ status: false, message: err.message }) | ||
} | ||
// Turn string from file to an Array | ||
let dataArray = JSON.parse(data); | ||
let dataObj = JSON.parse(data) | ||
updateCollection(db, dataArray, options) | ||
updateCollection(db, dataObj, options) | ||
.then(() => { | ||
@@ -70,11 +70,11 @@ resolve({ | ||
message: 'Collection successfully imported!' | ||
}); | ||
}) | ||
}) | ||
.catch(error => { | ||
reject({ status: false, message: error.message }); | ||
}); | ||
}); | ||
reject({ status: false, message: error.message }) | ||
}) | ||
}) | ||
} | ||
}).catch(error => console.error(error)); | ||
}; | ||
}).catch(error => console.error(error)) | ||
} | ||
@@ -85,20 +85,19 @@ /** | ||
* @param {any} db | ||
* @param {Array<any>} dataArray | ||
* @param {Array<string>} dateArray | ||
* @param {Array<string>} geoArray | ||
* @param {object} dataObj | ||
* @param {IImportOptions} options | ||
*/ | ||
const updateCollection = async ( | ||
db, | ||
dataArray: Array<any>, | ||
dataObj: object, | ||
options: IImportOptions = {} | ||
) => { | ||
for (var index in dataArray) { | ||
var collectionName = index; | ||
for (var doc in dataArray[index]) { | ||
if (dataArray[index].hasOwnProperty(doc)) { | ||
for (var index in dataObj) { | ||
var collectionName = index | ||
for (var doc in dataObj[index]) { | ||
if (dataObj[index].hasOwnProperty(doc)) { | ||
// asign document id for array type | ||
let docId = Array.isArray(dataArray[index]) ? uuidv1() : doc; | ||
if (dataArray[index][doc]['subCollection']) { | ||
const subCollections = dataArray[index][docId]['subCollection']; | ||
delete dataArray[index][doc]['subCollection']; | ||
let docId = Array.isArray(dataObj[index]) ? uuidv1() : doc | ||
if (!Array.isArray(dataObj[index])) { | ||
const subCollections = dataObj[index][docId]['subCollection'] | ||
delete dataObj[index][doc]['subCollection'] | ||
await startUpdating( | ||
@@ -108,8 +107,14 @@ db, | ||
docId, | ||
dataArray[index][doc], | ||
dataObj[index][doc], | ||
options | ||
); | ||
// Update sub collection | ||
await updateCollection(db, subCollections); | ||
) | ||
if (subCollections) { | ||
await updateCollection(db, subCollections, options) | ||
} | ||
} else { | ||
const subCollections = dataObj[index][doc]['subCollection'] | ||
delete dataObj[index][doc]['subCollection'] | ||
await startUpdating( | ||
@@ -119,5 +124,14 @@ db, | ||
docId, | ||
dataArray[index][doc], | ||
dataObj[index][doc], | ||
options | ||
); | ||
) | ||
if (subCollections) { | ||
for (const subIndex in subCollections) { | ||
const revivedSubCollection = {} | ||
const subCollectionPath = `${collectionName}/${docId}/${subIndex}` | ||
revivedSubCollection[subCollectionPath] = subCollections[subIndex] | ||
await updateCollection(db, revivedSubCollection, options) | ||
} | ||
} | ||
} | ||
@@ -127,3 +141,3 @@ } | ||
} | ||
}; | ||
} | ||
@@ -136,4 +150,3 @@ /** | ||
* @param data | ||
* @param dateArray | ||
* @param geoArray | ||
* @param options | ||
*/ | ||
@@ -150,3 +163,3 @@ | ||
if (options.dates && options.dates.length > 0) { | ||
updateTime(options.dates, data); | ||
updateTime(options.dates, data) | ||
} | ||
@@ -158,5 +171,10 @@ | ||
if (data.hasOwnProperty(ref)) { | ||
data[ref] = db.doc(data[ref]); | ||
// check type of the reference | ||
if (Array.isArray(data[ref])) { | ||
data[ref] = data[ref].map(ref => db.doc(ref)) | ||
} else { | ||
data[ref] = db.doc(data[ref]) | ||
} | ||
} | ||
}); | ||
}) | ||
} | ||
@@ -171,7 +189,7 @@ | ||
data[geo]._longitude | ||
); | ||
) | ||
} else { | ||
console.warn('Please check your geo parameters!!!', options.geos); | ||
console.warn('Please check your geo parameters!!!', options.geos) | ||
} | ||
}); | ||
}) | ||
} | ||
@@ -184,16 +202,16 @@ | ||
.then(() => { | ||
console.log(`${docId} was successfully added to firestore!`); | ||
console.log(`${docId} was successfully added to firestore!`) | ||
resolve({ | ||
status: true, | ||
message: `${docId} was successfully added to firestore!` | ||
}); | ||
}) | ||
}) | ||
.catch(error => { | ||
console.log(error); | ||
console.log(error) | ||
reject({ | ||
status: false, | ||
message: error.message | ||
}); | ||
}); | ||
}); | ||
}; | ||
}) | ||
}) | ||
}) | ||
} |
@@ -1,5 +0,5 @@ | ||
import { expect } from 'chai'; | ||
import request from 'request-promise'; | ||
import * as firestoreService from '../dist'; | ||
import { serviceAccount } from './serviceAccount'; | ||
import { expect } from 'chai' | ||
import request from 'request-promise' | ||
import * as firestoreService from '../dist' | ||
import { serviceAccount } from './serviceAccount' | ||
@@ -9,33 +9,33 @@ const app = firestoreService.initializeApp( | ||
serviceAccount.databaseUrl | ||
); | ||
) | ||
const backupAPI = | ||
'https://firebasestorage.googleapis.com/v0/b/firbase-function-helper-qa.appspot.com/o/import-to-firestore.json?alt=media&token=a0530902-8983-45a4-90c2-72c345c7a3d5'; | ||
'https://firebasestorage.googleapis.com/v0/b/firbase-function-helper-qa.appspot.com/o/import-to-firestore.json?alt=media&token=a0530902-8983-45a4-90c2-72c345c7a3d5' | ||
describe('initializeApp function test', () => { | ||
it('Initialize app', () => { | ||
expect(app).to.equal(true); | ||
}); | ||
expect(app).to.equal(true) | ||
}) | ||
it('Restore data from API', async () => { | ||
const backupData = await request(backupAPI); | ||
const backupData = await request(backupAPI) | ||
const status = await firestoreService.restore(JSON.parse(backupData), { | ||
dates: ['date'], | ||
geos: ['location'] | ||
}); | ||
expect(status.status).ok; | ||
}); | ||
}) | ||
expect(status.status).ok | ||
}) | ||
it('Get all collections', async () => { | ||
try { | ||
const all = await firestoreService.backups(); | ||
expect(Object.keys(all).length).is.greaterThan(0); | ||
const all = await firestoreService.backups() | ||
expect(Object.keys(all).length).is.greaterThan(0) | ||
} catch (error) { | ||
console.log(error); | ||
console.log(error) | ||
} | ||
}); | ||
}) | ||
it('Get an array of collections', async () => { | ||
const all = await firestoreService.backups(['test', 'users']); | ||
expect(Object.keys(all).length).is.equal(2); | ||
}); | ||
const all = await firestoreService.backups(['test', 'users']) | ||
expect(Object.keys(all).length).is.equal(2) | ||
}) | ||
@@ -48,12 +48,12 @@ it('Restore data with document id', async () => { | ||
geos: ['location'], | ||
refs: ['secondRef'] | ||
refs: ['secondRef', 'arrayRef'] | ||
} | ||
); | ||
expect(status.status).ok; | ||
) | ||
expect(status.status).ok | ||
const result = await firestoreService.backup('test'); | ||
const result = await firestoreService.backup('test') | ||
expect(result.test['first-key'].email).is.equal('dungnq@itbox4vn.com'); | ||
expect(result.test['first-key'].schedule.time._seconds).equals(1534046400); | ||
expect(typeof result.test['first-key'].secondRef).is.equal('object'); | ||
expect(result.test['first-key'].email).is.equal('dungnq@itbox4vn.com') | ||
expect(result.test['first-key'].schedule.time._seconds).equals(1534046400) | ||
expect(typeof result.test['first-key'].secondRef).is.equal('object') | ||
expect( | ||
@@ -63,4 +63,4 @@ result.test['first-key'].subCollection['test/first-key/details'][ | ||
].dogName | ||
).is.equal('hello'); | ||
}); | ||
).is.equal('hello') | ||
}) | ||
@@ -70,22 +70,17 @@ it('Restore data as an array without document id', async () => { | ||
'test/import-array-to-firestore.json' | ||
); | ||
expect(status.status).ok; | ||
}); | ||
) | ||
expect(status.status).ok | ||
}) | ||
it('Get a colection with sub-collection', async () => { | ||
try { | ||
const data = await firestoreService.backup('test'); | ||
const subCol = data['test']['first-key']['subCollection']; | ||
const data = await firestoreService.backup('test') | ||
const subCol = data['test']['first-key']['subCollection'] | ||
expect(subCol).is.exist; | ||
expect(Object.values(subCol).length).is.greaterThan(0); | ||
expect(subCol).is.exist | ||
expect(Object.values(subCol).length).is.greaterThan(0) | ||
} catch (error) { | ||
console.log(error); | ||
console.log(error) | ||
} | ||
}); | ||
it('Get one collection', async () => { | ||
const result = await firestoreService.backup('test'); | ||
expect(Object.keys(result).length).is.equal(1); | ||
}); | ||
}); | ||
}) | ||
}) |
@@ -5,3 +5,15 @@ { | ||
"name": "Dale Nguyen", | ||
"email": "dale@dalenguyen.me" | ||
"email": "dale@dalenguyen.me", | ||
"subCollection": { | ||
"details": [ | ||
{ | ||
"dogId": "2", | ||
"dogName": "hello" | ||
}, | ||
{ | ||
"dogName": "lala", | ||
"dogId": "2" | ||
} | ||
] | ||
} | ||
}, | ||
@@ -8,0 +20,0 @@ { |
@@ -33,2 +33,3 @@ { | ||
"secondRef": "test/second-key", | ||
"arrayRef": ["test/second-key", "test/second-key"], | ||
"subCollection": { | ||
@@ -35,0 +36,0 @@ "test/first-key/details": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45448
600
237
11
+ Addedregexp.prototype.flags@1.5.2(transitive)
- Removedregexp.prototype.flags@1.5.3(transitive)
Updatedfirebase-admin@^8.10.0