By Trevor Geise / Context
*Image Credit Tara Velis
MongoDB + NodeJs + Handlebars/Blaze
AWS -> Setup and configure a ton of disparate services
Create a Firebase project
1
$ npm install -g firebase-tools
$ npm install --save firebase
$ firebase login
$ firebase initInstall the Firebase CLI, NPM package, login and initiatlize
2
import firebase from 'firebase';
import 'firebase/firestore';
var firebaseConfig = {
apiKey: "api-key",
authDomain: "project-id.firebaseapp.com",
databaseURL: "https://project-id.firebaseio.com",
projectId: "project-id",
storageBucket: "project-id.appspot.com",
messagingSenderId: "sender-id",
};
firebase.initializeApp(firebaseConfig );Import Firebase and Firestore.
3
There is “solid evidence” of recent global warming due “mostly” to “human activity such as burning fossil fuels.” [agree, disagree]
Dan Kahan, Cultural Cognition Project, Yale
// main.js
let app;
firebase.auth().onAuthStateChanged(() => {
if (!app) {
app = new Vue({
el: '#app',
router,
store,
render: h => h(App)
});
}
});// store/auth/actions.js
submitLoginForm({ dispatch, commit }, data) {
return new Promise((resolve, reject) => {
firebase.auth()
.signInWithEmailAndPassword(data.email, data.pw)
.then(user => {
commit('setCurrentUser', user.user);
dispatch('fetchUserProfile');
resolve();
})
.catch(err => {
console.log(err);
reject(err);
});
});
},// store/auth/actions.js
submitRegisterForm({ commit, dispatch }, formData) {
return new Promise((resolve, reject) => {
firebase.auth()
.createUserWithEmailAndPassword(formData.email, formData.password)
.then(user => {
commit('setCurrentUser', user.user);
// add user document
fb.usersCollection
.doc(user.user.uid)
.set({
name: fromData.name,
// whatever data you want to set here
})
.then(() => {
resolve();
})
.catch(err => {
console.log(err);
reject(err);
});
})
.catch(err => {
console.log(err);
reject(err);
});
});
$ vue-cli-service build
$ firebase deploy// Create a root reference
var storageRef = firebase.storage().ref();
// Create a reference to 'mountains.jpg'
var mountainsRef = storageRef.child('mountains.jpg');
var file = ... // use the Blob or File API
mountainsRef.put(file).then(function(snapshot) {
console.log('Uploaded a blob or file!');
});// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
exports.helloWold = functions.https.onRequest((req, res) => {
res.status(200).send('hellow world');
return;
});firebase deploy --only functions// actions.js
testHelloWorld(undefined) {
return new Promise(async (resolve, reject) => {
const url = 'https://us-central1-MY_PROJECT.cloudfunctions.net/helloWorld';
try {
const result = await axios.post(url);
console.log(result); // 'hello world'
resolve(result);
} catch (e) {
console.log('failed', e);
reject();
}
});
},// Add Data
var db = firebase.firestore();
db.collection("users").add({
first: "Ada",
last: "Lovelace",
born: 1815
})
.then(function(docRef) {
console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
console.error("Error adding document: ", error);
});// Read Data
db.collection("users").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
});
});// Reactive data with VUEX: store/actions.js
let dataSub;
const actions = {
subscribeToData({ commit, state, dispatch }, authorId) {
dataSub = db.collection('articles').where('authorId', '==', authorId).onSnapshot(
query => {
query.docChanges().forEach(function(change) {
if (change.type === 'added' || change.type === 'modified') {
const data = change.doc.data();
data.id = change.doc.id;
commit('addToArticles', data);
}
if (change.type === 'removed') {
commit('removeFromArticles', change.doc.id);
}
});
},
err => {
console.log(err);
}
);
},
unsubscribeToData({ commit }) {
commit('emptyAuthors');
dataSub(); // closes listener
}
}Action
Mutation
Store
Firestore
Cloud Functions
Getters
Updating an element in an array is a pain, easy for an object value.
Query limitations from array.
// Mongo query based on array
// get all messages from these three authors
db.messages.find( {
authorId: {
$in: ['8290fah8ac', '9a0jffk33', 'a89f03n822']
}
})
/* In Firestore you have to write three different
queries and if you want reactive, then three
different listeners to handle. */
db.collection('messages')
.where('authorId','==', '8290fah8ac');
// You can query an array based on an input.
db.collection('test')
.where('authors','array-contains', authorId);
// Instead of an array of authorIds, you may want
// to save a map like so
authors: {
8290fah8ac: { id: 8290fah8ac, name: "Janet"},
9a0jffk33: { id: 9a0jffk33, name: "Jose"},
a89f03n822: { id: a89f03n822, name: "Lindsey"},
}
(Maps are just objects)
1MB limit
Firestore query is just as fast regardless of number of documents.
1 write/second limit
Try not to chain them together
Takes a while with cold starts
You can always use a different cloud function/lambda solution (cloudflare workers)
Might have to get redundant.
Format your schema based on what you'll be searching for and displaying.
Do you need data to be reactive?
exports.userUpdate = (functions, admin) => {
return functions.firestore.document('users/{userId}').onUpdate(async (change, context) => {
//initialize the database incase we need to do writes
const db = admin.firestore();
//initialize the return
const returnPromises = [];
// Get an object representing the current document
const newData = change.after.data();
// ...or the previous value before this update
const previousData = change.before.data();
const userId = change.after.id;
if (previousData.name !== newData.name || previousData.avatar !== newData.avatar) {
const messagesThatNeedUpdated = await db
.collection('messages')
.where(`authors.${userId}.id`, '==', userId)
.get();
messagesThatNeedUpdated.forEach(singleDoc => {
//get the doc data
const doc = singleDoc.data();
doc.id = singleDoc.id;
//author update document
const authorUpdate = {
id: userId,
name: newData.name,
avatar: newData.avatar
};
//get the update
const update = {};
const updateObj = authorUpdate;
update['authors.' + userId] = updateObj;
//make the update
returnPromises.push(
db
.collection('boards')
.doc(doc.id)
.update(update)
);
});
} else {
return 'no documents need to be modified';
}
return Promise.all(returnPromises);
});
};
Get duplicated data accurate with cloud functions triggered by the database.