Types for collection references, query building, and query result handling including filtering, ordering, and pagination.
Reference to a Firestore collection, extending Query with collection-specific operations.
class CollectionReference<T = DocumentData, T2 extends DocumentData = DocumentData> extends Query<T, T2> {
private constructor();
/** Collection ID */
readonly id: string;
/** Parent document reference, or null for root collections */
readonly parent: DocumentReference<DocumentData> | null;
/** Full collection path */
readonly path: string;
/** Get a document reference in this collection */
doc(documentPath?: string): DocumentReference<T>;
/** Add a new document to this collection */
add(data: T): Promise<DocumentReference<T>>;
/** Check if this reference equals another */
isEqual(other: CollectionReference<T>): boolean;
/** Convert this reference to use a different data type */
withConverter(converter: null): CollectionReference<DocumentData>;
withConverter<U>(
converter: FirestoreDataConverter<U>
): CollectionReference<U>;
}Base class for building and executing Firestore queries.
class Query<T = DocumentData, T2 extends DocumentData = DocumentData> {
protected constructor();
/** Firestore instance this query belongs to */
readonly firestore: FirebaseFirestore;
/** Filter documents where field matches condition */
where(
fieldPath: string | FieldPath,
opStr: WhereFilterOp,
value: any
): Query<T>;
/** Order results by field */
orderBy(
fieldPath: string | FieldPath,
directionStr?: OrderByDirection
): Query<T>;
/** Limit number of results */
limit(limit: number): Query<T>;
/** Limit to last N results (requires orderBy) */
limitToLast(limit: number): Query<T>;
/** Start results at document snapshot */
startAt(snapshot: DocumentSnapshot<any>): Query<T>;
/** Start results at field values */
startAt(...fieldValues: any[]): Query<T>;
/** Start results after document snapshot */
startAfter(snapshot: DocumentSnapshot<any>): Query<T>;
/** Start results after field values */
startAfter(...fieldValues: any[]): Query<T>;
/** End results before document snapshot */
endBefore(snapshot: DocumentSnapshot<any>): Query<T>;
/** End results before field values */
endBefore(...fieldValues: any[]): Query<T>;
/** End results at document snapshot */
endAt(snapshot: DocumentSnapshot<any>): Query<T>;
/** End results at field values */
endAt(...fieldValues: any[]): Query<T>;
/** Check if this query equals another */
isEqual(other: Query<T>): boolean;
/** Execute query and get results */
get(options?: GetOptions): Promise<QuerySnapshot<T>>;
/** Listen for query result changes */
onSnapshot(observer: {
next?: (snapshot: QuerySnapshot<T>) => void;
error?: (error: FirestoreError) => void;
complete?: () => void;
}): () => void;
onSnapshot(
options: SnapshotListenOptions,
observer: {
next?: (snapshot: QuerySnapshot<T>) => void;
error?: (error: FirestoreError) => void;
complete?: () => void;
}
): () => void;
onSnapshot(
onNext: (snapshot: QuerySnapshot<T>) => void,
onError?: (error: FirestoreError) => void,
onCompletion?: () => void
): () => void;
onSnapshot(
options: SnapshotListenOptions,
onNext: (snapshot: QuerySnapshot<T>) => void,
onError?: (error: FirestoreError) => void,
onCompletion?: () => void
): () => void;
/** Convert this query to use a different data type */
withConverter(converter: null): Query<DocumentData>;
withConverter<U>(converter: FirestoreDataConverter<U>): Query<U>;
}type OrderByDirection = 'desc' | 'asc';
type WhereFilterOp =
| '<' // Less than
| '<=' // Less than or equal
| '==' // Equal to
| '!=' // Not equal to
| '>=' // Greater than or equal
| '>' // Greater than
| 'array-contains' // Array contains value
| 'in' // Field value in array
| 'array-contains-any' // Array contains any of the values
| 'not-in'; // Field value not in arrayType-safe field path construction for nested fields.
class FieldPath {
/** Create a field path from field names */
constructor(...fieldNames: string[]);
/** Special field path representing document ID */
static documentId(): FieldPath;
/** Check if this field path equals another */
isEqual(other: FieldPath): boolean;
}import type { CollectionReference, DocumentData } from "@firebase/firestore-types";
interface User {
name: string;
email: string;
age: number;
}
async function manageCollection(collection: CollectionReference<User>) {
// Add new document with auto-generated ID
const docRef = await collection.add({
name: "Alice",
email: "alice@example.com",
age: 30
});
// Get specific document reference
const specificDoc = collection.doc("user-123");
// Get all documents in collection
const snapshot = await collection.get();
snapshot.forEach(doc => {
const userData = doc.data(); // Typed as User
console.log('User:', userData.name);
});
}import type { Query, WhereFilterOp, OrderByDirection } from "@firebase/firestore-types";
function buildQueries(usersCollection: CollectionReference<User>) {
// Simple where clause
const adults = usersCollection.where("age", ">=", 18);
// Multiple filters
const activeAdults = usersCollection
.where("age", ">=", 18)
.where("status", "==", "active");
// Array queries
const usersInCities = usersCollection
.where("city", "in", ["New York", "San Francisco", "Seattle"]);
// Ordering and limiting
const topUsers = usersCollection
.orderBy("score", "desc")
.limit(10);
// Pagination with cursors
const paginatedQuery = usersCollection
.orderBy("createdAt")
.startAfter(lastDocSnapshot)
.limit(20);
return { adults, activeAdults, usersInCities, topUsers, paginatedQuery };
}import type { FieldPath } from "@firebase/firestore-types";
interface UserProfile {
basic: {
name: string;
email: string;
};
preferences: {
theme: string;
notifications: boolean;
};
}
function queryNestedFields(collection: CollectionReference<UserProfile>) {
// Query nested field using dot notation
const darkThemeUsers = collection.where("preferences.theme", "==", "dark");
// Query nested field using FieldPath
const notificationUsers = collection.where(
new FieldPath("preferences", "notifications"),
"==",
true
);
// Order by nested field
const orderedByName = collection.orderBy("basic.name");
return { darkThemeUsers, notificationUsers, orderedByName };
}import type { QuerySnapshot, DocumentChange } from "@firebase/firestore-types";
function listenToQuery(query: Query<User>) {
const unsubscribe = query.onSnapshot({
next: (snapshot: QuerySnapshot<User>) => {
console.log(`Query returned ${snapshot.size} documents`);
// Process changes
const changes = snapshot.docChanges();
changes.forEach((change: DocumentChange<User>) => {
const userData = change.doc.data();
switch (change.type) {
case 'added':
console.log('New user:', userData.name);
break;
case 'modified':
console.log('Modified user:', userData.name);
break;
case 'removed':
console.log('Removed user:', userData.name);
break;
}
});
},
error: (error) => {
console.error('Query error:', error);
}
});
return unsubscribe;
}