or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

ai.mdanalytics.mdapp-check.mdauth-guard.mdauthentication.mddata-connect.mddatabase.mdfirebase-app.mdfirestore.mdfunctions.mdindex.mdmessaging.mdperformance.mdremote-config.mdstorage.mdvertexai.md
tile.json

firestore.mddocs/

Firestore

Cloud Firestore is Firebase's flexible, scalable NoSQL cloud database. It provides real-time synchronization, offline support, powerful querying capabilities, and automatic multi-region data replication. All Firestore functions are Zone-wrapped for proper Angular change detection.

Capabilities

Standalone Provider

Modern Angular standalone API for providing Firebase Firestore instances.

/**
 * Provides Firebase Firestore instance using standalone API
 * @param fn - Function that returns initialized Firestore instance
 * @returns Environment providers for dependency injection
 */
export function provideFirestore(fn: () => Firestore): EnvironmentProviders;

/**
 * Get Firebase Firestore instance
 * @param app - Optional Firebase app instance
 * @returns Firebase Firestore instance
 */
export function getFirestore(app?: FirebaseApp): Firestore;

NgModule Provider

Traditional NgModule API for providing Firebase Firestore instances.

/**
 * Firebase Firestore NgModule for traditional module-based setup
 */
export class FirestoreModule {
  static forRoot(): ModuleWithProviders<FirestoreModule>;
}

Angular Services

Injectable services for accessing Firebase Firestore instances in Angular components.

/**
 * Injectable service providing access to Firebase Firestore instance
 */
export class Firestore extends Firestore {}

/**
 * Collection of all Firebase Firestore instances
 */
export class FirestoreInstances extends Array<Firestore> {}

/**
 * Observable stream of Firebase Firestore instances
 */
export const firestoreInstance$: Observable<Firestore>;

Document Operations

Core functions for working with individual documents.

/**
 * Get document reference
 * @param firestore - Firestore instance
 * @param path - Document path (e.g., 'users/userId')
 * @returns Document reference
 */
export function doc(firestore: Firestore, path: string): DocumentReference;

/**
 * Get document reference with typed data
 * @param firestore - Firestore instance
 * @param path - Document path
 * @returns Typed document reference
 */
export function doc<T>(firestore: Firestore, path: string): DocumentReference<T>;

/**
 * Set document data (overwrites existing data)
 * @param ref - Document reference
 * @param data - Document data
 * @returns Promise that resolves when write completes
 */
export function setDoc<T>(ref: DocumentReference<T>, data: T): Promise<void>;

/**
 * Set document data with merge options
 * @param ref - Document reference
 * @param data - Partial document data
 * @param options - Set options with merge
 * @returns Promise that resolves when write completes
 */
export function setDoc<T>(
  ref: DocumentReference<T>,
  data: Partial<T>,
  options: SetOptions
): Promise<void>;

/**
 * Update document fields
 * @param ref - Document reference
 * @param data - Fields to update
 * @returns Promise that resolves when update completes
 */
export function updateDoc<T>(
  ref: DocumentReference<T>,
  data: Partial<T>
): Promise<void>;

/**
 * Update specific document fields with field paths
 * @param ref - Document reference
 * @param field - Field name or path
 * @param value - Field value
 * @param moreFieldsAndValues - Additional field-value pairs
 * @returns Promise that resolves when update completes
 */
export function updateDoc(
  ref: DocumentReference,
  field: string | FieldPath,
  value: any,
  ...moreFieldsAndValues: any[]
): Promise<void>;

/**
 * Delete document
 * @param ref - Document reference
 * @returns Promise that resolves when delete completes
 */
export function deleteDoc(ref: DocumentReference): Promise<void>;

/**
 * Get document snapshot
 * @param ref - Document reference
 * @returns Promise resolving to document snapshot
 */
export function getDoc<T>(ref: DocumentReference<T>): Promise<DocumentSnapshot<T>>;

Collection Operations

Functions for working with collections of documents.

/**
 * Get collection reference
 * @param firestore - Firestore instance
 * @param path - Collection path (e.g., 'users')
 * @returns Collection reference
 */
export function collection(firestore: Firestore, path: string): CollectionReference;

/**
 * Get typed collection reference
 * @param firestore - Firestore instance
 * @param path - Collection path
 * @returns Typed collection reference
 */
export function collection<T>(
  firestore: Firestore,
  path: string
): CollectionReference<T>;

/**
 * Add document to collection with auto-generated ID
 * @param ref - Collection reference
 * @param data - Document data
 * @returns Promise resolving to new document reference
 */
export function addDoc<T>(
  ref: CollectionReference<T>,
  data: T
): Promise<DocumentReference<T>>;

/**
 * Get documents from collection or query
 * @param query - Collection reference or query
 * @returns Promise resolving to query snapshot
 */
export function getDocs<T>(query: Query<T>): Promise<QuerySnapshot<T>>;

Querying

Advanced querying capabilities for filtering, ordering, and limiting data.

/**
 * Create query with constraints
 * @param query - Base query (collection reference or existing query)
 * @param queryConstraints - Query constraints (where, orderBy, limit, etc.)
 * @returns New query with applied constraints
 */
export function query<T>(
  query: Query<T>,
  ...queryConstraints: QueryConstraint[]
): Query<T>;

/**
 * Create where clause constraint
 * @param fieldPath - Field path to filter on
 * @param opStr - Comparison operator
 * @param value - Value to compare against
 * @returns Query constraint
 */
export function where(
  fieldPath: string | FieldPath,
  opStr: WhereFilterOp,
  value: any
): QueryConstraint;

/**
 * Create order by constraint
 * @param fieldPath - Field path to order by
 * @param directionStr - Sort direction ('asc' or 'desc')
 * @returns Query constraint
 */
export function orderBy(
  fieldPath: string | FieldPath,
  directionStr?: OrderByDirection
): QueryConstraint;

/**
 * Create limit constraint
 * @param limit - Maximum number of documents to return
 * @returns Query constraint
 */
export function limit(limit: number): QueryConstraint;

/**
 * Create limit to last constraint
 * @param limit - Maximum number of documents to return from end
 * @returns Query constraint
 */
export function limitToLast(limit: number): QueryConstraint;

/**
 * Create start at constraint
 * @param snapshot - Document snapshot to start at
 * @returns Query constraint
 */
export function startAt(snapshot: DocumentSnapshot): QueryConstraint;

/**
 * Create start at constraint with field values
 * @param fieldValues - Field values to start at
 * @returns Query constraint
 */
export function startAt(...fieldValues: any[]): QueryConstraint;

/**
 * Create start after constraint
 * @param snapshot - Document snapshot to start after
 * @returns Query constraint
 */
export function startAfter(snapshot: DocumentSnapshot): QueryConstraint;

/**
 * Create end at constraint
 * @param snapshot - Document snapshot to end at
 * @returns Query constraint
 */
export function endAt(snapshot: DocumentSnapshot): QueryConstraint;

/**
 * Create end before constraint
 * @param snapshot - Document snapshot to end before
 * @returns Query constraint
 */
export function endBefore(snapshot: DocumentSnapshot): QueryConstraint;

Real-time Listeners

Functions for listening to real-time document and collection changes.

/**
 * Listen to document changes
 * @param ref - Document reference
 * @param observer - Callback function or observer object
 * @returns Unsubscribe function
 */
export function onSnapshot<T>(
  ref: DocumentReference<T>,
  observer: (snapshot: DocumentSnapshot<T>) => void
): Unsubscribe;

/**
 * Listen to document changes with error handling
 * @param ref - Document reference
 * @param observer - Observer object with next, error, and complete handlers
 * @returns Unsubscribe function
 */
export function onSnapshot<T>(
  ref: DocumentReference<T>,
  observer: {
    next?: (snapshot: DocumentSnapshot<T>) => void;
    error?: (error: FirestoreError) => void;
    complete?: () => void;
  }
): Unsubscribe;

/**
 * Listen to query changes
 * @param query - Query to listen to
 * @param observer - Callback function or observer object
 * @returns Unsubscribe function
 */
export function onSnapshot<T>(
  query: Query<T>,
  observer: (snapshot: QuerySnapshot<T>) => void
): Unsubscribe;

/**
 * Listen to query changes with options
 * @param query - Query to listen to
 * @param options - Snapshot listener options
 * @param observer - Callback function or observer object
 * @returns Unsubscribe function
 */
export function onSnapshot<T>(
  query: Query<T>,
  options: SnapshotListenOptions,
  observer: (snapshot: QuerySnapshot<T>) => void
): Unsubscribe;

RxFire Observables

Reactive streams for Firestore data using RxJS Observables.

/**
 * Observable of document data
 * @param ref - Document reference
 * @returns Observable stream of document data or undefined
 */
export function docData<T>(ref: DocumentReference<T>): Observable<T | undefined>;

/**
 * Observable of document data with options
 * @param ref - Document reference
 * @param options - Observable options
 * @returns Observable stream of document data
 */
export function docData<T>(
  ref: DocumentReference<T>,
  options: { idField?: string }
): Observable<T | undefined>;

/**
 * Observable of document snapshots
 * @param ref - Document reference
 * @returns Observable stream of document snapshots
 */
export function docSnapshots<T>(ref: DocumentReference<T>): Observable<DocumentSnapshot<T>>;

/**
 * Observable of collection data
 * @param ref - Collection reference or query
 * @returns Observable stream of document data array
 */
export function collectionData<T>(ref: CollectionReference<T> | Query<T>): Observable<T[]>;

/**
 * Observable of collection data with options
 * @param ref - Collection reference or query
 * @param options - Observable options
 * @returns Observable stream of document data array
 */
export function collectionData<T>(
  ref: CollectionReference<T> | Query<T>,
  options: { idField?: string }
): Observable<T[]>;

/**
 * Observable of collection snapshots
 * @param ref - Collection reference or query
 * @returns Observable stream of query snapshots
 */
export function collectionSnapshots<T>(
  ref: CollectionReference<T> | Query<T>
): Observable<QuerySnapshot<T>>;

/**
 * Observable of collection changes with action types
 * @param ref - Collection reference or query
 * @returns Observable stream of document changes
 */
export function collectionChanges<T>(
  ref: CollectionReference<T> | Query<T>
): Observable<DocumentChange<T>[]>;

/**
 * Observable of sorted collection changes
 * @param ref - Collection reference or query
 * @param events - Array of change types to listen for
 * @returns Observable stream of sorted document changes
 */
export function sortedChanges<T>(
  ref: CollectionReference<T> | Query<T>,
  events?: DocumentChangeType[]
): Observable<DocumentChange<T>[]>;

/**
 * Observable audit trail of all document changes
 * @param ref - Collection reference or query
 * @returns Observable stream of audit trail entries
 */
export function auditTrail<T>(
  ref: CollectionReference<T> | Query<T>
): Observable<AuditTrail<T>[]>;

Transactions and Batches

Functions for atomic operations across multiple documents.

/**
 * Run transaction
 * @param firestore - Firestore instance
 * @param updateFunction - Transaction update function
 * @returns Promise resolving to transaction result
 */
export function runTransaction<T>(
  firestore: Firestore,
  updateFunction: (transaction: Transaction) => Promise<T>
): Promise<T>;

/**
 * Create write batch
 * @param firestore - Firestore instance
 * @returns WriteBatch instance for batched operations
 */
export function writeBatch(firestore: Firestore): WriteBatch;

/**
 * Transaction interface for atomic operations
 */
interface Transaction {
  get<T>(documentRef: DocumentReference<T>): Promise<DocumentSnapshot<T>>;
  set<T>(documentRef: DocumentReference<T>, data: T): Transaction;
  set<T>(documentRef: DocumentReference<T>, data: Partial<T>, options: SetOptions): Transaction;
  update<T>(documentRef: DocumentReference<T>, data: Partial<T>): Transaction;
  delete(documentRef: DocumentReference): Transaction;
}

/**
 * Write batch interface for batched operations
 */
interface WriteBatch {
  set<T>(documentRef: DocumentReference<T>, data: T): WriteBatch;
  set<T>(documentRef: DocumentReference<T>, data: Partial<T>, options: SetOptions): WriteBatch;
  update<T>(documentRef: DocumentReference<T>, data: Partial<T>): WriteBatch;
  delete(documentRef: DocumentReference): WriteBatch;
  commit(): Promise<void>;
}

Firestore Settings and Utilities

Configuration and utility functions for Firestore.

/**
 * Connect to Firestore emulator
 * @param firestore - Firestore instance
 * @param host - Emulator host
 * @param port - Emulator port
 * @param options - Optional connection settings
 */
export function connectFirestoreEmulator(
  firestore: Firestore,
  host: string,
  port: number,
  options?: { mockUserToken?: EmulatorMockTokenOptions | string }
): void;

/**
 * Enable network connectivity
 * @param firestore - Firestore instance
 * @returns Promise that resolves when network is enabled
 */
export function enableNetwork(firestore: Firestore): Promise<void>;

/**
 * Disable network connectivity
 * @param firestore - Firestore instance
 * @returns Promise that resolves when network is disabled
 */
export function disableNetwork(firestore: Firestore): Promise<void>;

/**
 * Enable IndexedDB persistence
 * @param firestore - Firestore instance
 * @param persistenceSettings - Optional persistence settings
 * @returns Promise that resolves when persistence is enabled
 */
export function enableIndexedDbPersistence(
  firestore: Firestore,
  persistenceSettings?: PersistenceSettings
): Promise<void>;

/**
 * Clear IndexedDB persistence
 * @param firestore - Firestore instance
 * @returns Promise that resolves when persistence is cleared
 */
export function clearIndexedDbPersistence(firestore: Firestore): Promise<void>;

/**
 * Wait for pending writes to complete
 * @param firestore - Firestore instance
 * @returns Promise that resolves when writes are complete
 */
export function waitForPendingWrites(firestore: Firestore): Promise<void>;

Types

Core Firestore Types

/**
 * Firestore database instance
 */
interface Firestore {
  readonly app: FirebaseApp;
}

/**
 * Document reference
 */
interface DocumentReference<T = DocumentData> {
  readonly id: string;
  readonly path: string;
  readonly parent: CollectionReference<T>;
  readonly firestore: Firestore;
}

/**
 * Collection reference
 */
interface CollectionReference<T = DocumentData> extends Query<T> {
  readonly id: string;
  readonly path: string;
  readonly parent: DocumentReference | null;
}

/**
 * Query interface
 */
interface Query<T = DocumentData> {
  readonly firestore: Firestore;
}

/**
 * Document snapshot
 */
interface DocumentSnapshot<T = DocumentData> {
  readonly id: string;
  readonly ref: DocumentReference<T>;
  readonly metadata: SnapshotMetadata;
  exists(): boolean;
  data(): T | undefined;
  get(fieldPath: string | FieldPath): any;
}

/**
 * Query snapshot
 */
interface QuerySnapshot<T = DocumentData> {
  readonly docs: QueryDocumentSnapshot<T>[];
  readonly size: number;
  readonly empty: boolean;
  readonly metadata: SnapshotMetadata;
  forEach(callback: (result: QueryDocumentSnapshot<T>) => void): void;
}

/**
 * Query document snapshot
 */
interface QueryDocumentSnapshot<T = DocumentData> extends DocumentSnapshot<T> {
  data(): T;
}

Query Types

/**
 * Where filter operators
 */
type WhereFilterOp =
  | '<'
  | '<='
  | '=='
  | '!='
  | '>='
  | '>'
  | 'array-contains'
  | 'in'
  | 'not-in'
  | 'array-contains-any';

/**
 * Order by direction
 */
type OrderByDirection = 'desc' | 'asc';

/**
 * Document change type
 */
type DocumentChangeType = 'added' | 'removed' | 'modified';

/**
 * Document change
 */
interface DocumentChange<T = DocumentData> {
  readonly type: DocumentChangeType;
  readonly doc: QueryDocumentSnapshot<T>;
  readonly oldIndex: number;
  readonly newIndex: number;
}

/**
 * Field path for nested field access
 */
class FieldPath {
  constructor(...fieldNames: string[]);
  static documentId(): FieldPath;
}

Options and Settings Types

/**
 * Set options for document writes
 */
interface SetOptions {
  readonly merge?: boolean;
  readonly mergeFields?: (string | FieldPath)[];
}

/**
 * Snapshot listener options
 */
interface SnapshotListenOptions {
  readonly includeMetadataChanges?: boolean;
}

/**
 * Snapshot metadata
 */
interface SnapshotMetadata {
  readonly hasPendingWrites: boolean;
  readonly fromCache: boolean;
}

/**
 * Persistence settings
 */
interface PersistenceSettings {
  readonly synchronizeTabs?: boolean;
  readonly experimentalForceOwningTab?: boolean;
}

Firestore Error Types

/**
 * Firestore error
 */
interface FirestoreError extends Error {
  readonly code: FirestoreErrorCode;
  readonly message: string;
}

/**
 * Firestore error codes
 */
type FirestoreErrorCode =
  | 'cancelled'
  | 'unknown'
  | 'invalid-argument'
  | 'deadline-exceeded'
  | 'not-found'
  | 'already-exists'
  | 'permission-denied'
  | 'resource-exhausted'
  | 'failed-precondition'
  | 'aborted'
  | 'out-of-range'
  | 'unimplemented'
  | 'internal'
  | 'unavailable'
  | 'data-loss'
  | 'unauthenticated';

Usage Examples

Basic Document Operations

import { Component, inject } from '@angular/core';
import { Firestore, doc, setDoc, getDoc, updateDoc, deleteDoc } from '@angular/fire/firestore';

@Component({
  selector: 'app-firestore-basic',
  template: `...`,
})
export class FirestoreBasicComponent {
  private firestore = inject(Firestore);

  async createUser(userId: string, userData: any) {
    const userRef = doc(this.firestore, 'users', userId);
    await setDoc(userRef, userData);
    console.log('User created');
  }

  async getUser(userId: string) {
    const userRef = doc(this.firestore, 'users', userId);
    const snapshot = await getDoc(userRef);
    
    if (snapshot.exists()) {
      console.log('User data:', snapshot.data());
      return snapshot.data();
    } else {
      console.log('User not found');
      return null;
    }
  }

  async updateUser(userId: string, updates: any) {
    const userRef = doc(this.firestore, 'users', userId);
    await updateDoc(userRef, updates);
    console.log('User updated');
  }

  async deleteUser(userId: string) {
    const userRef = doc(this.firestore, 'users', userId);
    await deleteDoc(userRef);
    console.log('User deleted');
  }
}

Collection Queries with RxFire

import { Component, inject } from '@angular/core';
import { 
  Firestore, 
  collection, 
  query, 
  where, 
  orderBy, 
  limit,
  collectionData 
} from '@angular/fire/firestore';
import { map } from 'rxjs/operators';

interface User {
  id: string;
  name: string;
  email: string;
  active: boolean;
  createdAt: Date;
}

@Component({
  selector: 'app-firestore-query',
  template: `
    <div *ngFor="let user of activeUsers$ | async">
      <h3>{{ user.name }}</h3>
      <p>{{ user.email }}</p>
    </div>
  `,
})
export class FirestoreQueryComponent {
  private firestore = inject(Firestore);

  // Get active users ordered by creation date
  activeUsers$ = collectionData(
    query(
      collection(this.firestore, 'users'),
      where('active', '==', true),
      orderBy('createdAt', 'desc'),
      limit(10)
    ),
    { idField: 'id' }
  ).pipe(
    map(users => users as User[])
  );

  // Get users by email domain
  getUsersByDomain(domain: string) {
    return collectionData(
      query(
        collection(this.firestore, 'users'),
        where('email', '>=', `@${domain}`),
        where('email', '<', `@${domain}\uf8ff`)
      ),
      { idField: 'id' }
    );
  }
}

Real-time Document Listening

import { Component, inject, OnDestroy } from '@angular/core';
import { Firestore, doc, onSnapshot } from '@angular/fire/firestore';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-realtime-doc',
  template: `
    <div *ngIf="userData">
      <h2>{{ userData.name }}</h2>
      <p>Status: {{ userData.status }}</p>
      <p>Last Updated: {{ userData.lastUpdated?.toDate() | date }}</p>
    </div>
  `,
})
export class RealtimeDocComponent implements OnDestroy {
  private firestore = inject(Firestore);
  private unsubscribe?: () => void;
  userData: any = null;

  ngOnInit() {
    const userRef = doc(this.firestore, 'users', 'user123');
    
    this.unsubscribe = onSnapshot(userRef, (snapshot) => {
      if (snapshot.exists()) {
        this.userData = snapshot.data();
        console.log('User data updated:', this.userData);
      } else {
        this.userData = null;
        console.log('User document does not exist');
      }
    }, (error) => {
      console.error('Error listening to user changes:', error);
    });
  }

  ngOnDestroy() {
    if (this.unsubscribe) {
      this.unsubscribe();
    }
  }
}

Transactions and Batches

import { Component, inject } from '@angular/core';
import { 
  Firestore, 
  doc, 
  runTransaction, 
  writeBatch,
  getDoc,
  increment
} from '@angular/fire/firestore';

@Component({
  selector: 'app-firestore-transaction',
  template: `...`,
})
export class FirestoreTransactionComponent {
  private firestore = inject(Firestore);

  async transferPoints(fromUserId: string, toUserId: string, points: number) {
    const fromRef = doc(this.firestore, 'users', fromUserId);
    const toRef = doc(this.firestore, 'users', toUserId);

    try {
      await runTransaction(this.firestore, async (transaction) => {
        const fromSnapshot = await transaction.get(fromRef);
        
        if (!fromSnapshot.exists()) {
          throw new Error('Source user does not exist');
        }

        const fromData = fromSnapshot.data();
        if (fromData['points'] < points) {
          throw new Error('Insufficient points');
        }

        transaction.update(fromRef, { points: increment(-points) });
        transaction.update(toRef, { points: increment(points) });
      });
      
      console.log('Points transferred successfully');
    } catch (error) {
      console.error('Transaction error:', error);
    }
  }

  async batchUpdateUsers(updates: { id: string; data: any }[]) {
    const batch = writeBatch(this.firestore);

    updates.forEach(update => {
      const userRef = doc(this.firestore, 'users', update.id);
      batch.update(userRef, update.data);
    });

    try {
      await batch.commit();
      console.log('Batch update completed');
    } catch (error) {
      console.error('Batch update error:', error);
    }
  }
}