Firebase Firestore

Introduction to Firebase Firestore with Python

Firebase Firestore is a flexible, scalable database for mobile, web, and server development. It allows you to store and sync data between your users in real-time. In this blog, we will explore how to integrate Firebase Firestore with Python and provide some useful tips and tricks along the way.

Setting Up Firestore in Python

To get started with Firestore in Python, you need to install the Firebase Admin SDK. You can do this using pip:

pip install firebase-admin python-dotenv

Next, you'll need to set up your Firebase project and download your service account key (JSON file). This key will allow your Python application to authenticate with Firebase.

Basic Configuration

Here’s a basic setup using the code provided:

import os
from firebase_admin import firestore
from firebase_admin import credentials, initialize_app
from dotenv import load_dotenv

load_dotenv(".env", override=True)

FIREBASE_CREDENTIALS_PATH = os.getenv("FIREBASE_CREDENTIALS_PATH")

cred = credentials.Certificate(FIREBASE_CREDENTIALS_PATH)

try:
    default_app = initialize_app(cred)
except:
    pass

db = firestore.client()

In this code:

  • We load environment variables using dotenv to keep sensitive information secure.

  • We initialize the Firebase app using the service account credentials.

Getting Store Information

def get_store_by_id(store_id: str):
    store_doc = db.collection("stores").document(str(store_id)).get()
    if not store_doc.exists:
        raise ValueError(f"Store ID {store_id} not found")
    store_dict = store_doc.to_dict()
    store_dict["id"] = store_doc.id
    return store_dict

This function fetches details of a specific store by its ID.

Retrieving Products from a Store

def get_products(store_id: str):
    products_ref = db.collection("stores").document(str(store_id)).collection("products")
    product_docs = products_ref.get()
    
    if not product_docs:
        return None
    
    product_list = []
    for product_doc in product_docs:
        product_dict = product_doc.to_dict()
        product_dict["id"] = product_doc.id
        product_list.append(product_dict)
    
    return product_list

This function retrieves all products associated with a specific store. It demonstrates how to navigate collections and subcollections in Firestore.

Code for Firestore Validation and Basic Operations

def validate_document_reference(doc_ref):
    """Validate if the document reference exists."""
    if not isinstance(doc_ref, firestore.DocumentReference):
        raise ValueError("Provided reference is not a DocumentReference.")
    
    doc = doc_ref.get()
    if not doc.exists:
        raise ValueError(f"Document {doc_ref.id} does not exist.")
    
    return doc.to_dict()

def retrieve_data(collection_name, document_id):
    """Retrieve data from a Firestore document."""
    doc_ref = db.collection(collection_name).document(document_id)
    return validate_document_reference(doc_ref)

def set_data(collection_name, document_id, data):
    """Set data in a Firestore document."""
    doc_ref = db.collection(collection_name).document(document_id)
    doc_ref.set(data)
    return f"Document {document_id} successfully set in {collection_name}."

def get_root_collection(collection_name):
    """Get all documents from the root collection."""
    collection_ref = db.collection(collection_name)
    docs = collection_ref.get()
    
    return {doc.id: doc.to_dict() for doc in docs}

def get_subcollection(parent_collection, parent_id, subcollection_name):
    """Get all documents from a subcollection."""
    subcollection_ref = db.collection(parent_collection).document(parent_id).collection(subcollection_name)
    docs = subcollection_ref.get()
    
    return {doc.id: doc.to_dict() for doc in docs}
    
# Example usage
if __name__ == "__main__":
    # Set some example data
    set_data("users", "user_1", {"name": "Alice", "age": 30})

    # Retrieve user data
    user_data = retrieve_data("users", "user_1")
    print("User Data:", user_data)

    # Get all users
    all_users = get_root_collection("users")
    print("All Users:", all_users)

    # Set up subcollections and retrieve them
    set_data("users", "user_1", {"orders": []})  # Assuming you want to initialize orders for user_1
    set_data("users/user_1/orders", "order_1", {"item": "Book", "quantity": 2})
    
    orders = get_subcollection("users", "user_1", "orders")
    print("User Orders:", orders)

Explanation of the Code

  • Initialization: The code begins by loading environment variables and initializing the Firebase app with the provided credentials.

  • Validation Functions:

    • validate_document_reference(doc_ref): Checks if the provided reference is an instance of DocumentReference and whether the document exists in Firestore.

  • Data Retrieval:

    • retrieve_data(collection_name, document_id): Retrieves data from a specific document after validating its reference.

  • Data Setting:

    • set_data(collection_name, document_id, data): Sets or updates data in a specified document.

  • Collection Management:

    • get_root_collection(collection_name): Retrieves all documents from a specified root collection.

    • get_subcollection(parent_collection, parent_id, subcollection_name): Retrieves all documents from a specified subcollection under a parent document.

Tips and Tricks

  1. Use Environment Variables: Always use environment variables for sensitive information like API keys or service account credentials. This helps keep your application secure.

  2. Handle Exceptions Gracefully: Use try-except blocks when fetching documents from Firestore to handle cases where documents may not exist.

  3. Optimize Data Retrieval: When fetching large datasets, consider paginating results or using queries to limit data returned.

  4. Data Structure: Design your Firestore database structure wisely. Use collections and subcollections effectively to maintain a clean hierarchy of data.

  5. Utilize Decorators: The provided code uses decorators like @dict_to_snake for converting dictionary keys. This can help maintain consistency in data formats throughout your application.

Conclusion

Integrating Firebase Firestore with Python opens up many possibilities for building powerful applications that require real-time data synchronization. By following the setup instructions and utilizing the provided functions, you can quickly start developing your own applications with Firestore as the backend database.With these tips and tricks, you'll be well on your way to mastering Firebase Firestore in Python!

Last updated