Search code examples
firebasereact-nativegoogle-cloud-firestore

Firestore Query: implement "AND" and "OR" logic


Is there a way to query for documents where the userId matches and the document started or ended this day? I know firestore supports "OR" operator but im not sure if im implementing the implicit "and" operator correctly

Im trying to achieve something like this

import { DocumentData,  collection, query, where, getDocs, orderBy, Timestamp, or, and } from "firebase/firestore";
export async function getSessionsForDay(day: Date, userId: String) {
   const sessionsRef = collection(db, "sessions")
   ///...
   let q = query(
        sessionsRef,
        (
            orderBy("createdAt"),
            where("user", "==", userId),
            or
                (
                    (
                        where("endedAt", ">=", Timestamp.fromDate(startOfDay)),
                        where("endedAt", "<=", Timestamp.fromDate(endOfDay))
                    ),
                    (
                        where("startedAt", ">=", Timestamp.fromDate(startOfDay)),
                        where("startedAt", "<=", Timestamp.fromDate(endOfDay))
                    )
                )
        )
    );

I prefer not to use two queries and combine the results, unless there are no other alternatives. The only issue with using two queries is that I would get a lot of duplicated data

EDIT: error using "and" operator

ReferenceError: Property 'and' doesn't exist
    at ?anon_0_ (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:236014:135)
    at next (native)
    at asyncGeneratorStep (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:6078:26)
    at _next (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:6097:29)
    at anonymous (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:6102:14)
    at tryCallTwo (/Users/kudo/01_Work/Repos/expo/expo/android/versioned-react-native/packages/react-native/ReactAndroid/hermes-engine/.cxx/MinSizeRel/3n472i6k/x86_64/lib/InternalBytecode/InternalBytecode.js:61:9)
    at doResolve (/Users/kudo/01_Work/Repos/expo/expo/android/versioned-react-native/packages/react-native/ReactAndroid/hermes-engine/.cxx/MinSizeRel/3n472i6k/x86_64/lib/InternalBytecode/InternalBytecode.js:216:25)
    at Promise (/Users/kudo/01_Work/Repos/expo/expo/android/versioned-react-native/packages/react-native/ReactAndroid/hermes-engine/.cxx/MinSizeRel/3n472i6k/x86_64/lib/InternalBytecode/InternalBytecode.js:82:14)
    at anonymous (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:6094:25)
    at apply (native)
    at fetchData (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:236063:27)
    at anonymous (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:235939:16)
    at commitHookEffectListMount (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:95740:38)
    at commitPassiveMountOnFiber (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:96941:44)
    at commitPassiveMountEffects_complete (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:96913:40)
    at commitPassiveMountEffects_begin (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:96903:47)
    at commitPassiveMountEffects (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:96893:40)
    at flushPassiveEffectsImpl (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:98567:34)
    at flushPassiveEffects (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:98523:43)
    at anonymous (http://192.168.1.32:8081/node_modules%5Cexpo%5CAppEntry.bundle//&platform=android&dev=true&hot=false&lazy=true:98356:34)

Solution

  • If you want to use an and condition inside your or condition, use the and function around the inner conditions.

    or(
        and(
            where("endedAt", ">=", Timestamp.fromDate(startOfDay)),
            where("endedAt", "<=", Timestamp.fromDate(endOfDay))
        ),
        and(
            where("startedAt", ">=", Timestamp.fromDate(startOfDay)),
            where("startedAt", "<=", Timestamp.fromDate(endOfDay))
        )
    )