GCP Cloud Firestore

Cloud Firestore is GCP's fully managed, serverless NoSQL document database. It stores data as documents organized into collections, similar to how a filing cabinet holds folders (collections) that contain individual files (documents). Firestore is designed for mobile, web, and server applications that need real-time data synchronization and offline support.

Unlike relational databases that store data in rigid rows and tables, Firestore stores data as flexible JSON-like documents. Each document can have different fields — perfect for applications where data structures change frequently, like user profiles, product catalogs, or chat messages.

Firestore vs Cloud SQL

FeatureCloud SQL (Relational)Firestore (NoSQL)
Data modelTables with fixed rows and columnsDocuments inside collections
SchemaStrict — all rows follow the same structureFlexible — each document can differ
ScalingVertical (bigger server)Automatic horizontal scaling
Real-time syncNoYes — client receives updates instantly
Offline supportNoYes — works without internet connection
Best forFinancial data, complex joinsMobile apps, real-time dashboards

Firestore Data Model

Database
└── Collection: "users"
    ├── Document: "user_001"
    │   ├── name: "Rahul Sharma"
    │   ├── email: "rahul@example.com"
    │   ├── age: 28
    │   └── Subcollection: "orders"
    │       └── Document: "order_A1"
    │           ├── product: "Laptop"
    │           ├── price: 49999
    │           └── status: "delivered"
    └── Document: "user_002"
        ├── name: "Priya Patel"
        ├── email: "priya@example.com"
        └── location: { city: "Mumbai", state: "Maharashtra" }

Each document can contain strings, numbers, booleans, arrays, maps (nested objects), timestamps, references to other documents, and even subcollections.

Reading and Writing Data

Python – Adding a Document

from google.cloud import firestore

db = firestore.Client()

# Add a document with an auto-generated ID
doc_ref = db.collection("users").add({
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "age": 28
})
print(f"Document added with ID: {doc_ref[1].id}")

Python – Setting a Document with a Specific ID

db.collection("users").document("user_001").set({
    "name": "Priya Patel",
    "email": "priya@example.com",
    "city": "Mumbai"
})

Python – Reading a Document

doc = db.collection("users").document("user_001").get()

if doc.exists:
    print(doc.to_dict())
else:
    print("Document not found.")

Python – Updating Specific Fields

db.collection("users").document("user_001").update({
    "age": 29,
    "city": "Delhi"
})

Python – Deleting a Document

db.collection("users").document("user_001").delete()

Querying Firestore

# Get all users in Mumbai
users_ref = db.collection("users")
query = users_ref.where("city", "==", "Mumbai")
docs = query.stream()

for doc in docs:
    print(doc.id, doc.to_dict())

# Compound query — city AND age
query = users_ref.where("city", "==", "Mumbai").where("age", ">=", 25)

# Order and limit results
query = users_ref.order_by("name").limit(10)

Note: Compound queries (multiple where clauses on different fields) require a composite index. Firestore will show an error with a direct link to create the index if one is missing.

Real-Time Listeners

Firestore's most powerful feature is real-time synchronization. Applications can subscribe to changes in a document or collection and receive updates instantly — without polling.

Real-Time Flow:
App A updates document "order_001" → status: "shipped"
                │
                ▼
Firestore detects the change
                │
                ▼
App B (subscribed to "order_001") receives update automatically
→ UI updates instantly showing "Shipped"
# Python real-time listener
def on_snapshot(doc_snapshot, changes, read_time):
    for doc in doc_snapshot:
        print(f"Update received: {doc.to_dict()}")

doc_ref = db.collection("orders").document("order_001")
doc_watch = doc_ref.on_snapshot(on_snapshot)

Transactions and Batched Writes

Transaction

A transaction reads and writes documents atomically. Either all operations succeed, or none do — preventing partial updates.

# Transfer credits between two users atomically
@firestore.transactional
def transfer_credits(transaction, from_ref, to_ref, amount):
    from_doc = from_ref.get(transaction=transaction)
    to_doc = to_ref.get(transaction=transaction)

    new_from_balance = from_doc.get("credits") - amount
    new_to_balance = to_doc.get("credits") + amount

    transaction.update(from_ref, {"credits": new_from_balance})
    transaction.update(to_ref, {"credits": new_to_balance})

transaction = db.transaction()
transfer_credits(transaction, db.document("users/u1"), db.document("users/u2"), 100)

Batched Write

A batch groups multiple write operations (set, update, delete) into one atomic operation. Up to 500 documents can be written in a single batch.

batch = db.batch()

batch.set(db.collection("users").document("u3"), {"name": "Ali", "city": "Pune"})
batch.update(db.collection("users").document("u1"), {"city": "Bengaluru"})
batch.delete(db.collection("users").document("u0"))

batch.commit()  # All three operations happen together

Firestore Security Rules

For mobile and web apps that connect to Firestore directly (without a backend server), Security Rules control who can read and write documents.

// Allow only authenticated users to read their own data
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null
                         && request.auth.uid == userId;
    }
  }
}

Key Takeaways

  • Firestore is a serverless NoSQL document database with automatic scaling.
  • Data is stored as documents inside collections — flexible, schema-free structures.
  • Real-time listeners push data changes to connected clients instantly.
  • Transactions ensure atomic reads and writes — all or nothing.
  • Batched writes group up to 500 document operations into one atomic operation.
  • Security Rules protect data when mobile/web apps connect directly to Firestore.

Leave a Comment