firestore-export-import
Advanced tools
Comparing version 0.3.1 to 0.3.2
# Change log | ||
> **Tags:** | ||
> - :boom: [Breaking Change] | ||
> | ||
> - :boom: [Breaking Change] | ||
> - :eyeglasses: [Spec Compliancy] | ||
> - :rocket: [New Feature] | ||
> - :bug: [Bug Fix] | ||
> - :memo: [Documentation] | ||
> - :nail_care: [Polish] | ||
> - :rocket: [New Feature] | ||
> - :bug: [Bug Fix] | ||
> - :memo: [Documentation] | ||
> - :nail_care: [Polish] | ||
--- | ||
## [0.3.2] - 2020-01-03 | ||
#### - :rocket: [New Feature] | ||
- Get data with all sub collectiosn with extra params | ||
#### - :nail_care: [Polish] | ||
- Updated packages | ||
## [0.3.1] - 2019-11-11 | ||
#### - :bug: [Bug Fix] | ||
#### - :bug: [Bug Fix] | ||
- Allow multi level time #33 | ||
## [0.3.0] - 2019-11-11 | ||
#### - :nail_care: [Polish] | ||
#### - :nail_care: [Polish] | ||
- Update packages | ||
- Added change log | ||
#### - :rocket: [New Feature] | ||
- Support time import max to two levels | ||
#### - :rocket: [New Feature] | ||
- Support time import max to two levels |
@@ -11,5 +11,4 @@ /** | ||
* @param {string} collectionName | ||
* @param {string} [subCollection=''] | ||
* @returns {Promise<any>} | ||
*/ | ||
export declare const backup: (collectionName: string, subCollection?: string) => Promise<any>; | ||
export declare const backup: (collectionName: string) => Promise<any>; |
@@ -15,5 +15,2 @@ "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);});} | ||
r[k]=a[j];return r;};var __importStar=(this&&this.__importStar)||function(mod){if(mod&&mod.__esModule)return mod;var result={};if(mod!=null)for(var k in mod)if(Object.hasOwnProperty.call(mod,k))result[k]=mod[k];result["default"]=mod;return result;};Object.defineProperty(exports,"__esModule",{value:true});var admin=__importStar(require("firebase-admin"));exports.getAllCollections=function(collectionNameArray){var db=admin.firestore();return new Promise(function(resolve){db.listCollections().then(function(snap){var paths=collectionNameArray;if(paths.length===0){snap.forEach(function(collection){return paths.push(collection.path);});} | ||
var promises=[];paths.forEach(function(segment){var result=exports.backup(segment);promises.push(result);});Promise.all(promises).then(function(value){var all=Object.assign.apply(Object,__spreadArrays([{}],value));resolve(all);});});});};exports.backup=function(collectionName,subCollection){if(subCollection===void 0){subCollection='';} | ||
return new Promise(function(resolve,reject){var db=admin.firestore();var data={};data[collectionName]={};var results=db.collection(collectionName).get().then(function(snapshot){snapshot.forEach(function(doc){data[collectionName][doc.id]=doc.data();});return data;}).catch(function(error){console.log(error);});results.then(function(dt){if(subCollection===''){resolve(dt);} | ||
else{console.log('Geting sub collection',subCollection);getSubCollection(db,data,dt,collectionName,subCollection).then(function(){resolve(data);}).catch(function(error){console.log(error);reject(error);});}}).catch(function(error){console.log(error);reject(error);});});};var getSubCollection=function(db,data,dt,collectionName,subCollection){return __awaiter(void 0,void 0,void 0,function(){var _i,_a,_b,key,value,subCollectionPath,subCollectionData;return __generator(this,function(_c){switch(_c.label){case 0:_i=0,_a=Object.entries([dt[collectionName]][0]);_c.label=1;case 1:if(!(_i<_a.length))return[3,4];_b=_a[_i],key=_b[0],value=_b[1];subCollectionPath=collectionName+'/'+key+'/'+subCollection;return[4,exports.backup(subCollectionPath)];case 2:subCollectionData=_c.sent();if(Object.keys(subCollectionData[subCollectionPath]).length>0){data[collectionName][key]['subCollection']=subCollectionData;} | ||
_c.label=3;case 3:_i++;return[3,1];case 4:return[2];}});});}; | ||
var promises=[];paths.forEach(function(segment){var result=exports.backup(segment);promises.push(result);});Promise.all(promises).then(function(value){var all=Object.assign.apply(Object,__spreadArrays([{}],value));resolve(all);});});});};exports.backup=function(collectionName){return __awaiter(void 0,void 0,void 0,function(){var db,data,documents,_i,_a,doc,subCollections,_b,subCollections_1,subCol,subColData,error_1;return __generator(this,function(_c){switch(_c.label){case 0:_c.trys.push([0,9,,10]);db=admin.firestore();data={};data[collectionName]={};return[4,db.collection(collectionName).get()];case 1:documents=_c.sent();_i=0,_a=documents.docs;_c.label=2;case 2:if(!(_i<_a.length))return[3,8];doc=_a[_i];return[4,doc.ref.listCollections()];case 3:subCollections=_c.sent();data[collectionName][doc.id]=doc.data();_b=0,subCollections_1=subCollections;_c.label=4;case 4:if(!(_b<subCollections_1.length))return[3,7];subCol=subCollections_1[_b];return[4,exports.backup(collectionName+"/"+doc.id+"/"+subCol.id)];case 5:subColData=_c.sent();data[collectionName][doc.id]['subCollection']=subColData;_c.label=6;case 6:_b++;return[3,4];case 7:_i++;return[3,2];case 8:return[2,data];case 9:error_1=_c.sent();console.error(error_1);throw new Error(error_1);case 10:return[2];}});});}; |
@@ -14,6 +14,5 @@ import * as admin from 'firebase-admin'; | ||
* @param {string} collectionName | ||
* @param {string} subCollection | ||
* @return {json} | ||
*/ | ||
export declare const backup: (collectionName: string, subCollection?: string) => Promise<any>; | ||
export declare const backup: (collectionName: string) => Promise<any>; | ||
/** | ||
@@ -20,0 +19,0 @@ * Restore data to firestore |
@@ -1,5 +0,4 @@ | ||
"use strict";var __importStar=(this&&this.__importStar)||function(mod){if(mod&&mod.__esModule)return mod;var result={};if(mod!=null)for(var k in mod)if(Object.hasOwnProperty.call(mod,k))result[k]=mod[k];result["default"]=mod;return result;};Object.defineProperty(exports,"__esModule",{value:true});var admin=__importStar(require("firebase-admin"));exports.admin=admin;var restoreService=__importStar(require("./import"));var backupService=__importStar(require("./export"));exports.initializeApp=function(serviceAccount,databaseURL){admin.initializeApp({credential:admin.credential.cert(serviceAccount),databaseURL:databaseURL});admin.firestore().settings({timestampsInSnapshots:true});return true;};exports.backup=function(collectionName,subCollection){if(subCollection===void 0){subCollection='';} | ||
return backupService.backup(collectionName,subCollection);};exports.restore=function(fileName,dateArray,geoArray){if(dateArray===void 0){dateArray=[];} | ||
"use strict";var __importStar=(this&&this.__importStar)||function(mod){if(mod&&mod.__esModule)return mod;var result={};if(mod!=null)for(var k in mod)if(Object.hasOwnProperty.call(mod,k))result[k]=mod[k];result["default"]=mod;return result;};Object.defineProperty(exports,"__esModule",{value:true});var admin=__importStar(require("firebase-admin"));exports.admin=admin;var restoreService=__importStar(require("./import"));var backupService=__importStar(require("./export"));exports.initializeApp=function(serviceAccount,databaseURL){admin.initializeApp({credential:admin.credential.cert(serviceAccount),databaseURL:databaseURL});admin.firestore().settings({timestampsInSnapshots:true});return true;};exports.backup=function(collectionName){return backupService.backup(collectionName);};exports.restore=function(fileName,dateArray,geoArray){if(dateArray===void 0){dateArray=[];} | ||
if(geoArray===void 0){geoArray=[];} | ||
return restoreService.restore(fileName,dateArray,geoArray);};exports.backups=function(collectionNameArray){if(collectionNameArray===void 0){collectionNameArray=[];} | ||
return backupService.getAllCollections(collectionNameArray);}; |
{ | ||
"name": "firestore-export-import", | ||
"version": "0.3.1", | ||
"version": "0.3.2", | ||
"description": "NPM package for backup and restore Firebase Firestore", | ||
@@ -31,5 +31,5 @@ "main": "dist/index.js", | ||
"devDependencies": { | ||
"@types/chai": "^4.2.4", | ||
"@types/chai": "^4.2.7", | ||
"@types/mocha": "^5.2.7", | ||
"@types/node": "^12.12.7", | ||
"@types/node": "^13.1.2", | ||
"chai": "^4.2.0", | ||
@@ -40,7 +40,7 @@ "jsmin": "^1.0.1", | ||
"request-promise": "^4.2.5", | ||
"ts-node": "^8.5.0", | ||
"typescript": "^3.7.2" | ||
"ts-node": "^8.5.4", | ||
"typescript": "^3.7.4" | ||
}, | ||
"dependencies": { | ||
"firebase-admin": "^8.7.0" | ||
"firebase-admin": "^8.9.0" | ||
}, | ||
@@ -47,0 +47,0 @@ "engines": { |
# firestore-export-import | ||
[![GitHub version](https://badge.fury.io/gh/dalenguyen%2Ffirestore-backup-restore.svg)](https://badge.fury.io/gh/dalenguyen%2Ffirestore-backup-restore) | ||
[![GitHub version](https://badge.fury.io/gh/dalenguyen%2Ffirestore-backup-restore.svg)](https://badge.fury.io/gh/dalenguyen%2Ffirestore-backup-restore) | ||
[![Build Status](https://travis-ci.org/dalenguyen/firestore-backup-restore.svg?branch=master)](https://travis-ci.org/dalenguyen/firestore-backup-restore) | ||
@@ -9,7 +9,7 @@ [![David badge](https://david-dm.org/dalenguyen/firestore-backup-restore.svg)](https://david-dm.org/dalenguyen/firestore-backup-restore) | ||
You can export and import data from firestore with sub collection. | ||
You can export and import data from firestore with sub collection. | ||
## Installation | ||
## Installation | ||
Install using [__npm__](https://www.npmjs.com/). | ||
Install using [**npm**](https://www.npmjs.com/). | ||
@@ -22,5 +22,5 @@ ```sh | ||
You can __Generate New Private Key__ from Project Settings from [Firebase Console](https://console.firebase.google.com). | ||
You can **Generate New Private Key** from Project Settings from [Firebase Console](https://console.firebase.google.com). | ||
After that you need to copy the __databaseURL__ for initiating the App. | ||
After that you need to copy the **databaseURL** for initiating the App. | ||
@@ -46,7 +46,7 @@ ## Usage | ||
firestoreService | ||
.backup('collection-name', 'sub-collection-optional') | ||
.then(data => console.log(JSON.stringify(data))) | ||
.backup('collection-name') | ||
.then(data => console.log(JSON.stringify(data))); | ||
``` | ||
If the sub collection exists, it will be saved under __subCollection__. | ||
Sub collections will be added under **'subCollection'** object. | ||
@@ -67,4 +67,3 @@ ### Get all collections data | ||
console.log(JSON.stringify(collections)); | ||
}) | ||
}); | ||
``` | ||
@@ -74,6 +73,6 @@ | ||
This code will help you to import data from a JSON file to firestore. You have two options: | ||
This code will help you to import data from a JSON file to firestore. You have two options: | ||
+ Restore from a JSON file from your local machine | ||
+ Restore from a JSON from a HTTP request | ||
- Restore from a JSON file from your local machine | ||
- Restore from a JSON from a HTTP request | ||
@@ -101,6 +100,10 @@ This will return a Promise<{status: boolean, message: string}> | ||
// The array of date and location fields are optional | ||
firestoreService.restore('your-file-path.json', ['date1', 'date2.date3'], ['location1', 'location2']); | ||
firestoreService.restore( | ||
'your-file-path.json', | ||
['date1', 'date2.date3'], | ||
['location1', 'location2'] | ||
); | ||
``` | ||
* Note that the date array only support two levels now. If you pass ['date1.date2.date3'], it won't work. | ||
- Note that the date array only support two levels now. If you pass ['date1.date2.date3'], it won't work. | ||
@@ -116,3 +119,3 @@ #### For HTTP Request | ||
The JSON is formated as below. The collection name is __test__. __first-key__ and __second-key__ are document ids. | ||
The JSON is formated as below. The collection name is **test**. **first-key** and **second-key** are document ids. | ||
@@ -119,0 +122,0 @@ ```json |
import * as admin from 'firebase-admin'; | ||
/** | ||
* Get data from all collections | ||
* Get data from all collections | ||
* Suggestion from jcummings2 and leningsv | ||
@@ -9,92 +9,60 @@ * @param {Array<string>} collectionNameArray | ||
export const getAllCollections = (collectionNameArray): Promise<any> => { | ||
const db = admin.firestore(); | ||
// get all the root-level paths | ||
return new Promise((resolve) => { | ||
db.listCollections().then((snap) => { | ||
let paths = collectionNameArray; | ||
if(paths.length === 0) { // get all collections | ||
snap.forEach((collection) => paths.push(collection.path)); | ||
} | ||
// fetch in parallel | ||
let promises = []; | ||
paths.forEach((segment) => { | ||
let result = backup(segment); | ||
promises.push(result); | ||
}); | ||
// assemble the pieces into one object | ||
Promise.all(promises).then((value) => { | ||
let all = Object.assign({}, ...value); | ||
resolve(all); | ||
}); | ||
}); | ||
}) | ||
} | ||
const db = admin.firestore(); | ||
// get all the root-level paths | ||
return new Promise(resolve => { | ||
db.listCollections().then(snap => { | ||
let paths = collectionNameArray; | ||
if (paths.length === 0) { | ||
// get all collections | ||
snap.forEach(collection => paths.push(collection.path)); | ||
} | ||
// fetch in parallel | ||
let promises = []; | ||
paths.forEach(segment => { | ||
let result = backup(segment); | ||
promises.push(result); | ||
}); | ||
// assemble the pieces into one object | ||
Promise.all(promises).then(value => { | ||
let all = Object.assign({}, ...value); | ||
resolve(all); | ||
}); | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Backup data from firestore | ||
* | ||
* @param {string} collectionName | ||
* @param {string} [subCollection=''] | ||
* @returns {Promise<any>} | ||
* | ||
* @param {string} collectionName | ||
* @returns {Promise<any>} | ||
*/ | ||
export const backup = (collectionName: string, subCollection: string = ''): Promise<any> => { | ||
return new Promise((resolve, reject) => { | ||
const db = admin.firestore(); | ||
let data = {}; | ||
export const backup = async (collectionName: string): Promise<any> => { | ||
try { | ||
const db = admin.firestore(); | ||
let data = {}; | ||
data[collectionName] = {}; | ||
data[collectionName] = {}; | ||
const documents = await db.collection(collectionName).get(); | ||
let results = db.collection(collectionName) | ||
.get() | ||
.then(snapshot => { | ||
snapshot.forEach(doc => { | ||
data[collectionName][doc.id] = doc.data(); | ||
}) | ||
return data; | ||
}) | ||
.catch(error => { | ||
console.log(error); | ||
}) | ||
for (const doc of documents.docs) { | ||
const subCollections = await doc.ref.listCollections(); | ||
results.then(dt => { | ||
if (subCollection === '') { | ||
resolve(dt); | ||
} else { | ||
console.log('Geting sub collection', subCollection) | ||
getSubCollection(db, data, dt, collectionName, subCollection).then(() => { | ||
resolve(data) | ||
}).catch(error => { | ||
console.log(error); | ||
reject(error); | ||
}) | ||
} | ||
}).catch(error => { | ||
console.log(error) | ||
reject(error); | ||
}) | ||
}) | ||
data[collectionName][doc.id] = doc.data(); | ||
} | ||
for (const subCol of subCollections) { | ||
const subColData = await backup( | ||
`${collectionName}/${doc.id}/${subCol.id}` | ||
); | ||
data[collectionName][doc.id]['subCollection'] = subColData; | ||
} | ||
} | ||
/** | ||
* Get sub collection from a document if possible | ||
* | ||
* @param {any} db | ||
* @param {any} data | ||
* @param {any} dt | ||
* @param {any} collectionName | ||
* @param {any} subCollection | ||
*/ | ||
const getSubCollection = async (db, data, dt, collectionName, subCollection) => { | ||
for (let [key, value] of Object.entries([dt[collectionName]][0])) { | ||
const subCollectionPath = collectionName + '/' + key + '/' + subCollection; | ||
let subCollectionData = await backup(subCollectionPath) | ||
if (Object.keys(subCollectionData[subCollectionPath]).length > 0) { | ||
data[collectionName][key]['subCollection'] = subCollectionData; | ||
} | ||
} | ||
} | ||
return data; | ||
} catch (error) { | ||
console.error(error); | ||
throw new Error(error); | ||
} | ||
}; |
@@ -7,37 +7,40 @@ import * as admin from 'firebase-admin'; | ||
* Initialize Firebase App | ||
* | ||
* @param {any} serviceAccount | ||
* | ||
* @param {any} serviceAccount | ||
* @param {any} databaseURL | ||
*/ | ||
export const initializeApp = (serviceAccount: string, databaseURL: string) => { | ||
admin.initializeApp({ | ||
credential: admin.credential.cert(serviceAccount), | ||
databaseURL: databaseURL | ||
}); | ||
admin.firestore().settings({ timestampsInSnapshots: true }); | ||
return true; | ||
} | ||
admin.initializeApp({ | ||
credential: admin.credential.cert(serviceAccount), | ||
databaseURL: databaseURL | ||
}); | ||
admin.firestore().settings({ timestampsInSnapshots: true }); | ||
return true; | ||
}; | ||
export { admin } | ||
export { admin }; | ||
/** | ||
* Backup data from firestore | ||
* | ||
* | ||
* @param {string} collectionName | ||
* @param {string} subCollection | ||
* @return {json} | ||
*/ | ||
export const backup = (collectionName: string, subCollection: string = '') => { | ||
return backupService.backup(collectionName, subCollection); | ||
} | ||
export const backup = (collectionName: string) => { | ||
return backupService.backup(collectionName); | ||
}; | ||
/** | ||
* Restore data to firestore | ||
* @param fileName | ||
* @param dateArray | ||
* @param geoArray | ||
* @param fileName | ||
* @param dateArray | ||
* @param geoArray | ||
*/ | ||
export const restore = (fileName: string, dateArray: Array<string> = [], geoArray: Array<string> = []) => { | ||
return restoreService.restore(fileName, dateArray, geoArray); | ||
} | ||
export const restore = ( | ||
fileName: string, | ||
dateArray: Array<string> = [], | ||
geoArray: Array<string> = [] | ||
) => { | ||
return restoreService.restore(fileName, dateArray, geoArray); | ||
}; | ||
@@ -49,3 +52,3 @@ /** | ||
export const backups = (collectionNameArray: Array<string> = []) => { | ||
return backupService.getAllCollections(collectionNameArray); | ||
} | ||
return backupService.getAllCollections(collectionNameArray); | ||
}; |
@@ -6,55 +6,67 @@ import { expect } from 'chai'; | ||
const app = firestoreService.initializeApp(serviceAccount, 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'; | ||
const app = firestoreService.initializeApp( | ||
serviceAccount, | ||
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'; | ||
describe ('initializeApp function test', () => { | ||
it ('Initialize app', () => { | ||
expect(app).to.equal(true); | ||
}); | ||
describe('initializeApp function test', () => { | ||
it('Initialize app', () => { | ||
expect(app).to.equal(true); | ||
}); | ||
it('Get a colection with sub-collection', async () => { | ||
try { | ||
const data = await firestoreService.backup('test', 'details'); | ||
const subCol = data['test']['first-key']['subCollection']; | ||
expect(subCol).is.exist; | ||
expect(Object.values(subCol).length).is.greaterThan(0); | ||
} catch (error) { | ||
console.log(error) | ||
} | ||
}); | ||
it('Get a colection with sub-collection', async () => { | ||
try { | ||
const data = await firestoreService.backup('test'); | ||
const subCol = data['test']['first-key']['subCollection']; | ||
it ('Get all collections', async () => { | ||
try { | ||
const all = await firestoreService.backups(); | ||
expect(Object.keys(all).length).is.greaterThan(0); | ||
} catch (error) { | ||
console.log(error) | ||
} | ||
}); | ||
expect(subCol).is.exist; | ||
expect(Object.values(subCol).length).is.greaterThan(0); | ||
} catch (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); | ||
}); | ||
it('Get all collections', async () => { | ||
try { | ||
const all = await firestoreService.backups(); | ||
expect(Object.keys(all).length).is.greaterThan(0); | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
}); | ||
it ('Restore data', async () => { | ||
let status = await firestoreService.restore('test/import-to-firestore.json', ['date', 'schedule.time', 'three.level.time'], ['location']); | ||
expect(status.status).ok; | ||
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) | ||
}); | ||
it('Get an array of collections', async () => { | ||
const all = await firestoreService.backups(['test', 'users']); | ||
expect(Object.keys(all).length).is.equal(2); | ||
}); | ||
it ('Restore data from API', async () => { | ||
const backupData = await request(backupAPI); | ||
const status = await firestoreService.restore(JSON.parse(backupData), ['date'], ['location']); | ||
expect(status.status).ok; | ||
}) | ||
it('Restore data', async () => { | ||
let status = await firestoreService.restore( | ||
'test/import-to-firestore.json', | ||
['date', 'schedule.time', 'three.level.time'], | ||
['location'] | ||
); | ||
expect(status.status).ok; | ||
it ('Get one collection', async () => { | ||
const result = await firestoreService.backup('test'); | ||
expect(Object.keys(result).length).is.equal(1); | ||
}); | ||
}) | ||
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); | ||
}); | ||
it('Restore data from API', async () => { | ||
const backupData = await request(backupAPI); | ||
const status = await firestoreService.restore( | ||
JSON.parse(backupData), | ||
['date'], | ||
['location'] | ||
); | ||
expect(status.status).ok; | ||
}); | ||
it('Get one collection', async () => { | ||
const result = await firestoreService.backup('test'); | ||
expect(Object.keys(result).length).is.equal(1); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
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
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
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
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
175
39784
527
Updatedfirebase-admin@^8.9.0