CPRG-306 Week 10

Cloud Firestore


Agenda

  • NoSQL Databases
  • Cloud Firestore
    • Rules
    • CRUD Operations
  • Next.js Dynamic Routing
  • Demo: Blogging Platform

NoSQL Databases

  • Non-relational databases
  • No fixed schema, flexible data model
  • Large scale
  • Real-time updates
  • Example apps: social media, maps, blogs, IoT, drawing apps

Terminology

  • Collection: Array of documents (table)
  • Document: JSON object (row)
  • Field, Value: Key-value pair (column, cell)
  • Subcollection: Collection within a document (nested table)
  • Query: Retrieve data from a collection
  • Rules: Security and validation

Design Considerations

  • Data model
    • Typically, one query/document per screen
  • Denormalization, no joins
  • Query performance, Reads vs Writes
  • Security

Cloud Firestore

  • Serverless, managed NoSQL database
  • Real-time updates
  • Scalable
  • Integration with Firebase Authentication

Comparison to JS Objects

FeatureJavaScript ObjectsFirestore Documents
Basic StructureKey-value pairsKey-value pairs
Data TypesSupports all JS data types + functionsSupports basic types, no functions
Nested DataSupports nested objects and arraysDocuments can contain subcollections

Comparison to JS Objects (cont'd)

FeatureJavaScript ObjectsFirestore Documents
Data Size LimitsLimited only by runtime memory1 MB per document

Rules

  • Security and validation rules
  • Firestore Security Rules are written in a custom language
  • Rules are evaluated in order
  • allow or deny access to documents
  • request object contains information about the request, e.g. request.auth for authentication

Rules Example

  • Allow anyone to read. Write only if user is authenticated.
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read: if true;
      allow write: if request.auth != null;
    }
  }
}

CRUD Operations

  • Create, Read, Update, Delete
  • Example: Create a document
db.collection("blog-posts").add({
  title: "Hello, World!",
  content: "This is my first post.",
});

Read a Document

  • doc() is a reference to a document
  • getDoc() is an asynchronous function that returns a DocumentSnapshot
  • doc.data() is a method that returns the document data
const docRef = doc(db, "blog-posts", id);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
  console.log("Document data:", docRef.data());
} else {
  console.log("No such document!");
}

Read All Documents

  • collection() is a reference to a collection
  • getDocs() is an asynchronous function that is used to retrieve all documents in a collection
const ref = collection(db, "blog-posts");
const docs = await getDocs(ref);
docs.forEach((doc) => {
  console.log(doc.id, " => ", doc.data());
});

Update a Document

  • updateDoc() is an asynchronous function that updates a document
const docRef = doc(db, "blog-posts", id);
await updateDoc(docRef, {
  title: "New Title",
  content: "New Content",
});

Delete a Document

  • deleteDoc() is an asynchronous function that deletes a document
const docRef = doc(db, "blog-posts", id);
await deleteDoc(docRef);

Accessing Subcollections

  • collection() and doc() can be used to access subcollections too
  • Example: Suppose we have a collection of users, each with a collection of items
// Get a reference to the items collection for a specific user
const itemsCollection = collection(db, "users", userId, "items");
 
// Or, get a reference to a specific item document
const itemDoc = doc(db, "users", userId, "items", itemId);

Next.js Routing

  • Next.js uses a file-system based router where folders are used to define routes
  • page.js is a special file is used to make route segments publicly accessible
  • e.g. app/about/page.js will be accessible at http://localhost:3000/about

But what if we want to create dynamic routes like /blog/123?


Next.js Dynamic Routing

  • Folder name is enclosed in square brackets app/blog/[id]/page.js
  • prop params is a promise resolving to an object with the route parameters

Dynamic Route Example

https://github.com/warsylewicz/webdev2-demos/tree/master/app/week-10-dynamic-routing (opens in a new tab)


Coding Demo

  • Add Cloud Firestore to the Week 9 Demo

    • In the menu on the left, click "Build" and then "Firestore Database"
    • Add to the existing Firebase project
    • Choose "Start in test mode"
  • Demo a simple blog app with Next.js and Cloud Firestore