Books/Firebase Essentials/Firestore Database Basics

    Firestore Database Basics

    Firestore Database Basics

    Firestore is Firebase's primary database. It's where your app stores and retrieves data. Let's understand how it works and learn the essential operations.

    How Firestore Organizes Data

    Firestore uses a collection → document structure:

    Firestore Database
    ├── users (collection)
    │   ├── user1 (document) → { name: "Alice", email: "alice@example.com" }
    │   ├── user2 (document) → { name: "Bob", email: "bob@example.com" }
    │   └── user3 (document) → { name: "Carol", email: "carol@example.com" }
    ├── posts (collection)
    │   ├── post1 (document) → { title: "Hello World", author: "user1", ... }
    │   └── post2 (document) → { title: "Firebase Guide", author: "user2", ... }
    └── settings (collection)
        └── appConfig (document) → { theme: "dark", version: "1.0" }
    

    Key concepts:

    • Collection — A group of documents (like a folder). Examples: users, posts, products
    • Document — A single record with fields (like a file). Has a unique ID
    • Fields — Key-value pairs inside a document (like name: "Alice")
    • Document ID — A unique identifier. Can be auto-generated or custom

    Firestore vs. SQL Databases

    If you've heard of SQL databases (PostgreSQL, MySQL), here's how Firestore compares:

    SQLFirestore
    TableCollection
    RowDocument
    ColumnField
    Primary KeyDocument ID

    What to ask your AI: "I'm designing a [type of app]. What collections and documents should I create in Firestore?"

    Supported Data Types

    Firestore documents can store these types:

    TypeExampleNotes
    String"Hello"Text
    Number42, 3.14Integers and decimals
    Booleantrue, false
    TimestampTimestamp.now()Date/time
    Array["a", "b", "c"]Ordered list
    Map (Object){ city: "NYC" }Nested object
    NullnullEmpty value
    Referencedoc(db, "users/user1")Link to another document
    GeoPointnew GeoPoint(lat, lng)Location

    CRUD Operations

    CRUD stands for Create, Read, Update, Delete — the four basic database operations. Let's learn each one.

    Setup (Used in All Examples)

    import { getFirestore, collection, doc, addDoc, getDoc, getDocs,
             updateDoc, deleteDoc, query, where, orderBy, Timestamp } from "firebase/firestore";
    
    const db = getFirestore();

    Create — Adding Documents

    Add a document with an auto-generated ID:

    // Firestore generates a unique ID for you
    const docRef = await addDoc(collection(db, "users"), {
      name: "Alice",
      email: "alice@example.com",
      role: "user",
      createdAt: Timestamp.now(),
    });
    
    console.log("Document created with ID:", docRef.id);

    Add a document with a custom ID:

    import { setDoc } from "firebase/firestore";
    
    // You choose the ID
    await setDoc(doc(db, "users", "alice123"), {
      name: "Alice",
      email: "alice@example.com",
      role: "user",
      createdAt: Timestamp.now(),
    });

    When to use which:

    • Auto ID (addDoc) — Most of the time. IDs like xK7nR2pQ...
    • Custom ID (setDoc) — When you need a predictable ID (e.g., using a user's auth UID)

    Read — Getting Documents

    Get a single document by ID:

    const docSnap = await getDoc(doc(db, "users", "alice123"));
    
    if (docSnap.exists()) {
      console.log("User data:", docSnap.data());
      // { name: "Alice", email: "alice@example.com", ... }
    } else {
      console.log("No such document!");
    }

    Get all documents in a collection:

    const querySnapshot = await getDocs(collection(db, "users"));
    
    querySnapshot.forEach((doc) => {
      console.log(doc.id, "=>", doc.data());
    });

    Query with filters:

    // Get users with role "admin"
    const q = query(
      collection(db, "users"),
      where("role", "==", "admin")
    );
    const snapshot = await getDocs(q);
    
    // Get posts ordered by date, newest first
    const q2 = query(
      collection(db, "posts"),
      where("isPublished", "==", true),
      orderBy("createdAt", "desc")
    );

    Common query operators: ==, !=, <, <=, >, >=, in, array-contains

    What to ask your AI: "Write a Firestore query that gets all [items] where [condition], sorted by [field]."

    Update — Modifying Documents

    Update specific fields (without overwriting the entire document):

    await updateDoc(doc(db, "users", "alice123"), {
      email: "newalice@example.com",
      updatedAt: Timestamp.now(),
    });
    // Only email and updatedAt change — all other fields stay the same

    Overwrite an entire document:

    await setDoc(doc(db, "users", "alice123"), {
      name: "Alice Updated",
      email: "newalice@example.com",
      role: "admin",
      createdAt: Timestamp.now(),
    });
    // ⚠️ This replaces the entire document — any fields not included are deleted

    Delete — Removing Documents

    await deleteDoc(doc(db, "users", "alice123"));

    Note: Deleting a document does NOT delete its subcollections. If a user document has a subcollection of orders, those orders remain.

    Real-Time Listeners

    One of Firestore's superpowers is real-time updates. Instead of fetching data once, you can listen for changes:

    import { onSnapshot } from "firebase/firestore";
    
    // Listen to a single document
    const unsubscribe = onSnapshot(doc(db, "users", "alice123"), (doc) => {
      console.log("Current data:", doc.data());
      // This runs EVERY TIME the document changes
    });
    
    // Listen to a collection (or query)
    const unsubscribe2 = onSnapshot(
      query(collection(db, "messages"), orderBy("createdAt")),
      (snapshot) => {
        const messages = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data()
        }));
        console.log("Messages:", messages);
        // This runs whenever any message is added, changed, or deleted
      }
    );
    
    // Stop listening when you're done
    unsubscribe();
    unsubscribe2();

    Real-time listeners are perfect for chat apps, live dashboards, and collaborative features.

    What to ask your AI: "Add a real-time listener that updates my React component whenever [collection] changes."

    Structuring Your Data

    Good data structure makes everything easier. Here are common patterns:

    Flat Collections (Most Common)

    users/
      userId1 → { name, email, role }
      userId2 → { name, email, role }
    
    posts/
      postId1 → { title, body, authorId, createdAt }
      postId2 → { title, body, authorId, createdAt }
    

    Reference other documents by storing their ID (e.g., authorId points to a user).

    Subcollections

    users/
      userId1/
        orders/
          orderId1 → { total, items, status }
          orderId2 → { total, items, status }
    

    Use subcollections when data "belongs to" a parent document.

    General Rules

    1. Keep documents small — Don't store huge arrays. If a list grows unbounded, use a subcollection instead
    2. Duplicate data when it speeds up reads — It's OK to store a user's name in a post document (denormalization)
    3. Think about your queries first — Structure data based on how you'll read it, not how it's logically related

    What to ask your AI: "I'm building a [type of app] with [these features]. How should I structure my Firestore collections?"

    Security Rules — Who Can Read/Write

    Firestore Rules control access to your data. They live in firestore.rules:

    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
    
        // Anyone can read published posts
        match /posts/{postId} {
          allow read: if resource.data.isPublished == true;
          allow write: if request.auth != null;
        }
    
        // Users can only read/write their own data
        match /users/{userId} {
          allow read, write: if request.auth != null && request.auth.uid == userId;
        }
      }
    }
    

    Key variables in rules:

    • request.auth — The currently logged-in user (null if not logged in)
    • request.auth.uid — The user's ID
    • resource.data — The existing document data
    • request.resource.data — The incoming data (for writes)

    What to ask your AI: "Write Firestore security rules for my app. Here's who should access what: [describe access patterns]."

    What's Next?

    You know how Firestore works! The next tutorial shows you how to connect Firebase to your React or Node.js app with proper configuration.

    What to ask your AI: "Create a Firestore service file with TypeScript functions for CRUD operations on my [collection]."


    🌐 www.genai-mentor.ai