2022-04-08

Firebase snippets for CRUD and Auth (version 9)

Collection of Firebase snippets for my future use

  • posts

    • title content owner createdAt modifiedAt isPublished
  • users

    • email password

Get started

  • Go to Firebase console
  • Add project
  • Create database from Firestore Database (Cloud Firestore) menu on the left
    • I'm not using Realtime Database here
    • I can still listen for realtime updates with Firestore Database

Prep/config

npm i firebase
// firebase.js
import { initializeApp } from "firebase/app"
import { getFirestore } from "firebase/firestore"
import { getAuth } from "firebase/auth"
 
const firebaseConfig = {
  apiKey: "",
  authDomain: "",
  projectId: "",
  storageBucket: "",
  messagingSenderId: "",
  appId: "",
}
 
const app = initializeApp(firebaseConfig)
 
const db = getFirestore(app)
const auth = getAuth(app)
 
export { db, auth }

CRUD

// import config from above
import { db } from "./firebase"
 
// VS Code will auto import if you start typing
import {
  collection,
  doc,
  setDoc,
  serverTimestamp,
  getDoc,
  onSnapshot,
  deleteDoc,
  query,
  where,
  orderBy,
  limit,
} from "firebase/firestore"

Create - setDoc

// Document ID is auto-generated by Firebase
const docRef = doc(collection(db, "posts"))
await setDoc(docRef, {
  title,
  content,
  createdAt: serverTimestamp(),
  modifiedAt: serverTimestamp(),
})

If your field needs to be unique, set the value as document ID

// Document ID is set with given string
await setDoc(doc(db, "users", "set-the-userId-123"), {
  email: "",
  password: "",
})
// Document ID is set with given string
await setDoc(
  doc(db, "users", "set-the-userId-123"),
  // Convert Firebase custom UserImpl object -> JavaScript object
  JSON.parse(JSON.stringify(userCredentials.user))
)

Read - getDoc (single document)

const docRef = doc(db, "users", post.owner)
const docSnap = await getDoc(docRef)
 
if (docSnap.exists) {
  console.log(docSnap.data())
} else {
  console.log("No such document!")
}

Read - getDocs (not realtime)

const colRef = collection(db, "posts")
const snapshot = await getDocs(colRef)
snapshot.docs.map((doc) => {
  console.log(doc.data())
  return doc.data()
})

Read - onSnapshot (realtime updates)

// Without query
const colRef = collection(db, "posts")
onSnapshot(colRef, (snap) => {
  snap.docs.forEach((doc) => {
    console.log(doc.id)
    console.log(doc.data())
  })
})
// Using query
const colRef = collection(db, "posts")
const q = query(colRef, where("isPublished", "==", "true"), orderBy("createdAt", "desc"), limit(10))
 
onSnapshot(q, (snap) => {
  snap.docs.forEach((doc) => {
    console.log(doc.id)
    console.log(doc.data())
  })
})
// Mixed with some react code
import { useState, useEffect } from "react";
 
export const PostList = () => {
  const [posts, setPosts] = useState([]);
 
  useEffect(() => {
    const docRef = collection(db, "posts");
    const q = query(docRef, orderBy("createdAt", "desc"));
 
    const unsubscribe = onSnapshot(q, (snap) => {
      setPosts(
        snap.docs.map((doc) => ({
          ...doc.data(),
          id: doc.id,
        }))
      );
    });
 
    return () => unsubscribe();
  }, []);
 
  return (
    <div>
      {posts && posts.map((post) => (
          {post.title}
      ))}
    </div>
  );
}

Update - setDoc

const docRef = doc(db, "posts", post.id)
await setDoc(
  docRef,
  {
    title: newTitle,
    content: newContent,
    modifiedAt: serverTimestamp(),
  },
  { merge: true }
)

Delete - deleteDoc

const docRef = doc(db, "posts", post.id)
await deleteDoc(docRef)

Auth

import { db, auth } from "./firebase"
 
import {
  onAuthStateChanged,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  signOut,
  sendPasswordResetEmail,
  AuthErrorCodes,
} from "firebase/auth"

Signup

// Create user to Firebase `Authentication`
const userCredentials = await createUserWithEmailAndPassword(auth, "email", "password")
console.log(userCredentials.user)
 
// Add created user to Firebase `Firestore Database`
await setDoc(
  doc(db, "users", userCredentials.user.uid),
  // Convert Firebase custom UserImpl object -> JavaScript object
  JSON.parse(JSON.stringify(userCredentials.user))
)

Login

const userCredentials = await signInWithEmailAndPassword(auth, "email", "password")
console.log(userCredentials.user)

Logout

await signOut(auth)

Password reset

await sendPasswordResetEmail(auth, "email")

Error handling

try {
  const userCredentials = await signInWithEmailAndPassword(auth, "email", "password");
} catch (error) {
  if (error.code == AuthErrorCodes.USER_DELETED) {
    console.log("user-not-found");
  } else if (error.code == AuthErrorCodes.INVALID_PASSWORD) {
    console.log("wrong-password");
  }
  ...
}

Setting an observer on the Auth object - onAuthStateChanged

// Mixed with some react code
// UerContext.js
export const UserProvider = ({ children }) => {
  const [user, setUser] = useState(null);
 
  useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        console.log("onAuthStateChanged: " + user.email);
        setUser(user);
      } else {
        console.log("onAuthStateChanged: no user");
        setUser(null);
      }
    });
  }, []);
 
  ...