-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathexportFirestoreDB.js
199 lines (183 loc) · 5.46 KB
/
exportFirestoreDB.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Imports
const admin = require("firebase-admin");
const fs = require("fs");
const { Parser } = require("json2csv");
// Loading service account key to access Firestore database
var serviceAccount = require("./src/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
var db = admin.firestore();
const schema = {
admins: {},
quizzes: {},
responses: {},
sessions: {}
};
/**
* Fetches the entire Firestore database located at dbRef.
* @param {firebase.database.Reference} dbRef - Reference to the Firestore database.
* @param {Object} aux - The JSON schema.
* @param {Object} curr - The outputted JSON is dumped here.
*/
const dump = (dbRef, aux, curr) => {
return Promise.all(
Object.keys(aux).map(collection => {
return dbRef
.collection(collection)
.get()
.then(data => {
let promises = [];
data.forEach(doc => {
const data = doc.data();
if (!curr[collection]) {
curr[collection] = {
data: {},
type: "collection"
};
curr[collection].data[doc.id] = {
data,
type: "document"
};
} else {
curr[collection].data[doc.id] = data;
}
promises.push(
dump(
dbRef.collection(collection).doc(doc.id),
aux[collection],
curr[collection].data[doc.id]
)
);
});
return Promise.all(promises);
});
})
).then(() => {
return curr;
});
};
/**
* Restructures and flattens JSON object by removing unnecessary keys.
* @param {Object} json - Complex, unflattened JSON Object.
* @returns {Object} - Cleaned JSON Object.
*/
const cleanData = json => {
// Flattens collections
for (var collection in json) {
if (
json[collection].hasOwnProperty("data") &&
typeof json[collection] == "object"
) {
json[collection] = json[collection]["data"];
}
// Flattens documents in each collection
for (var document in json[collection]) {
if (
json[collection][document].hasOwnProperty("data") &&
typeof json[collection] == "object"
) {
json[collection][document] = json[collection][document]["data"];
}
}
}
// Changing object value structure into arrays
for (collection in json) {
var arr = [];
for (document in json[collection]) {
json[collection][document]["id"] = document;
arr.push(json[collection][document]);
}
json[collection] = arr;
}
// Convert timestamps to datetime strings
for (collection in json) {
for (var item in json[collection]) {
if (json[collection][item].hasOwnProperty("datetime")) {
json[collection][item]["datetime"] = getDateTime(
json[collection][item]["datetime"]
);
}
}
}
delete json.admins; // No need to export admins collection
return json;
};
const json2Csv = (json, collection) => {
var fields = [];
var unwind = [];
if (collection === "sessions") {
fields = ["id", "quiz", "sessionName", "type", "datetime", "participants"];
unwind = [
"participants"
// "participants.id",
// "participants.firstname",
// "participants.lastname",
// "participants.gender",
// "participants.race",
// "participants.age",
// "participants.zipcode",
// "participants.email"
];
} else if (collection === "quizzes") {
fields = ["id", "name", "audienceType", "questions"];
unwind = [
"questions"
// "questions.type",
// "questions.question",
// "questions.correctAnswer",
// "questions.answers"
];
} else {
fields = ["id", "pid", "quiz", "session", "datetime", "pre", "post"];
}
const json2csvParser = new Parser({ fields, unwind: unwind });
const csv = json2csvParser.parse(json);
return csv;
};
/**
* Converts a timestamp object into a readable datetime string.
* @param {Object} timestamp - A Javascript Date object representing a timestamp.
* @returns {string} A readable datetime string in en-US format (e.g. August 1, 2019, 10:59 AM).
*/
const getDateTime = timestamp => {
const date = timestamp.toDate();
return date.toLocaleString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
hour: "2-digit",
minute: "2-digit"
});
};
// Calling dump with schema and output answer
let aux = { ...schema };
let answer = {};
dump(db, aux, answer)
.then(answer => {
cleanData(answer);
//console.log(answer);
/** Uncomment the lines below to also allow exporting in JSON format */
// fs.writeFile("output.json", JSON.stringify(answer, null, 2), err => {
// if (err) throw err;
// else console.log("Exported to output.json");
// });
let sessions = json2Csv(answer["sessions"], "sessions");
let quizzes = json2Csv(answer["quizzes"], "quizzes");
let responses = json2Csv(answer["responses"], "responses");
fs.writeFile("sessions.csv", sessions, err => {
if (err) throw err;
else console.log("Exported to sessions.csv");
});
fs.writeFile("quizzes.csv", quizzes, err => {
if (err) throw err;
else console.log("Exported to quizzes.csv");
});
fs.writeFile("responses.csv", responses, err => {
if (err) throw err;
else console.log("Exported to responses.csv");
});
})
.catch(error => {
console.log(error);
});