使用多个条件 where 子句的 Firebase 版本 9

Rya*_*anY 7 javascript firebase google-cloud-firestore

我正在将一个项目从 Firebase 版本 8 更新到版本 9。我有条件过滤查询,其结构过去如下:

let query = db.collection("collectionName").orderBy("timestamp")

if (filters.selectedStaff) {
    query = query.where("id", "==", filters.selectedStaff.id);
    }
if (filters.selectedStudent) {
    query = query.where("studentIDs", "array-contains", filters.selectedStudent.id);
    }
Run Code Online (Sandbox Code Playgroud)

Then the query gets executed in a hook that rerenders everytime the filters change. Using Version 8, this works perfectly.

In version 9, queries are now build to follow a format where each query is passed as a parameter to the query function. A normal query would look like:

query(collection(db, "collectionName"), where("id", "==", filters.selectedStaff.id), where("studentIDs", "array-contains", filters.selectedStudent.id), orderBy("timestamp"))
Run Code Online (Sandbox Code Playgroud)

You can still store the where function as a variable, and pass that variable as a parameter to the query function:

let w1 = where("id", "==", filters.selectedStaff.id)
let w2 = where("studentIDs", "array-contains", filters.selectedStudent.id)
query(collection(db, "collectionName"), w1, w2, orderBy(timestamp))
Run Code Online (Sandbox Code Playgroud)

But, the problem I haven't figured out how to solve, is how to make where clauses conditional. It doesn't seem like firebase allows a where clause value to be any. For example, making w1 default to:

let w1 = where("id", "==", "*")
Run Code Online (Sandbox Code Playgroud)

If you try to make the operator also a variable and default to anything other than ==, like != :

let w1 = where("id", "!=", "")
Run Code Online (Sandbox Code Playgroud)

Firebase forces you to set the primary sort by the field in the where clause which won't working if you're trying to sort by another field like I am (timestamp).

Ultimately, the workaround that works is to create a field in each document that has the same value, like a boolean true value and then set all your where clauses to be equal to that initially, and then dynamically change:

let w1 = where("randomField", "==", true)
let w2 = where("randomField", "==", true)
if(filters.selectedStaff){
    w1 = where("id", "==", filters.selectedStaff.id)
}
if(filters.selectedStudent){
    w2 = where("studentIDs", "array-contains", filters.selectedStudent.id)
}
query(collection(db, "collectionName"), w1, w2, orderBy(timestamp))
Run Code Online (Sandbox Code Playgroud)

While this works, it feels like a really unnecessary workaround and I wanted to see if anyone know of a better way to accomplish the same outcome.

Dha*_*raj 16

您可以继续使用现有逻辑,只是语法发生了变化。尝试重构代码,如下所示:

let q = query(collection("db", "collectionName"), orderBy("timestamp")); 

if (filters.selectedStaff) {
  q = query(q, where("id", "==", filters.selectedStaff.id));
}

if (filters.selectedStudent) {
  q = query(q, where("studentIDs", "array-contains", filters.selectedStudent.id));
}

const snapshot = await getDocs(q);
Run Code Online (Sandbox Code Playgroud)

另一种方法是有条件地将这些条件推送到数组中:

const conditions = [orderBy("timestamp")]


if (filters.selectedStaff) {
  conditions.push(where("id", "==", filters.selectedStaff.id));
}

if (filters.selectedStudent) {
  conditions.push(where("studentIDs", "array-contains", filters.selectedStudent.id));
}

const q = query(collection(db, "collectionName"), ...conditions);
// Do note the spread operator                     ^

const snapshot = await getDocs(q);
Run Code Online (Sandbox Code Playgroud)