Hany Habib
Hany Habib

Reputation: 1405

Dynamic Where Conditions With Firestore and Typescript

I am trying to implement Repository Pattern with Firestore Firebase and TypeScript.

Code:

import { firestore } from "firebase-admin";
import { ISearchCriteria } from './ISearchCriteria'

//export class selectQuery<T> {
//    constructor(private query: firestore.Query<T>) { }
//}

export class DBContext {
    static current: DBContext = new DBContext();
    private db: firestore.Firestore;

    private constructor() {
        this.db = firestore();
    }

    collection(collectionName: string): firestore.CollectionReference<firestore.DocumentData> {
        return this.db.collection(collectionName);
    }

    public async where<T extends object>(collectionName: string, searchCriteria: ISearchCriteria[]): Promise<T[]> {
        var snapShot = this.collection(collectionName);
        for (var i = 0; i < searchCriteria.length; i++) {
            snapShot = snapShot.where(searchCriteria[i].fieldName, searchCriteria[i].filterOp, searchCriteria[i].value);
        }
        let res = await snapShot.get();
        return res.docs.map<T>(doc => ({ id: doc.id, ...doc.data() }) as T);
    }


    async get<T extends object>(collectionName: string): Promise<T[]> {
        let res = await this.collection(collectionName).get();
        return res.docs.map<T>(doc => ({ id: doc.id, ...doc.data() } as T));
    }

    async create<T extends object>(collectionName: string, item: T): Promise<T> {
        return (await this.collection(collectionName).add(item)) as T;
    }

    async update<T extends object>(collectionName: string, id: string, item: T): Promise<firestore.WriteResult> {
        var docRef = this.collection(collectionName).doc(id);
        return await docRef.update(item);
    }

    async delete<T extends object>(collectionName: string, id: string): Promise<firestore.WriteResult> {
        return await this.collection(collectionName).doc(id).delete();
    }
}

I followed the example here: Firestore: Multiple conditional where clauses.

But i am getting the following error : dbcontext.ts:23:13 - error TS2740: Type 'Query<DocumentData>' is missing the following properties from type 'CollectionReference<DocumentData>': id, parent, path, listDocuments, and 2 more. its failing in the mentioned below line

            snapShot = snapShot.where(searchCriteria[i].fieldName, searchCriteria[i].filterOp, searchCriteria[i].value);

ISearchCriteria:

    import { firestore } from "firebase-admin";
    export interface ISearchCriteria {
        fieldName: string | firestore.FieldPath,
        filterOp: FirebaseFirestore.WhereFilterOp,
        value: any
    }

Upvotes: 3

Views: 2689

Answers (2)

Gaurav Saluja
Gaurav Saluja

Reputation: 713

const getDocuments = (collection: string, queries: QueryWhereClause[]) => {
  let collectionRef: firebase.firestore.Query<firebase.firestore.DocumentData> = firestore.collection(collection);
  if (queries && queries.length) {
    for (const query of queries) {
      collectionRef = collectionRef.where(
        query.field,
        query.condition,
        query.value
      );
    }
  }
  return collectionRef.get();
};

Adding (firebase.firestore.Query) as my collection type worked.

let collectionRef: firebase.firestore.Query<firebase.firestore.DocumentData> = firestore.collection(collection);

Upvotes: 1

Doug Stevenson
Doug Stevenson

Reputation: 317362

The problem is that your collection() method returns a CollectionReference, but where() returns a Query. TypeScript is telling you that you can't assign a Query object to a CollectionReference variable.

If you look at the API documentation, you'll see that CollectionReference is actually a subclass of Query (it just returns all documents in the collection). When you call where(), you're building a new Query that filters the documents from the prior Query.

Try making your collection() return a Query instead so you can safely reassign snapShot:

collection(collectionName: string): firestore.Query<firestore.DocumentData> {
    return this.db.collection(collectionName);
}

BTW, your variable called snapShot isn't a snapshot - it should probably be called query.

Upvotes: 5

Related Questions