【问题标题】:Firebase Version 9 using multiple conditional where clausesFirebase 版本 9 使用多个条件 where 子句
【发布时间】:2021-11-07 17:48:11
【问题描述】:

我正在将一个项目从 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);
    }

然后查询在每次过滤器更改时重新呈现的钩子中执行。使用版本 8,这可以完美运行。

在版本 9 中,现在构建查询以遵循每个查询作为参数传递给查询函数的格式。一个普通的查询应该是这样的:

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

您仍然可以将 where 函数存储为变量,并将该变量作为参数传递给查询函数:

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

但是,我还没有想出如何解决的问题是如何使 where 子句有条件。 firebase 似乎不允许 where 子句值是任何值。例如,将 w1 默认设置为:

let w1 = where("id", "==", "*")

如果您尝试使运算符也成为变量并默认为 == 以外的任何内容,例如 != :

let w1 = where("id", "!=", "")

Firebase 强制您按 where 子句中的字段设置主要排序,如果您尝试按像 I am(时间戳)这样的另一个字段进行排序,这将不起作用。

最终,可行的解决方法是在每个文档中创建一个具有相同值的字段,例如布尔真值,然后将所有 where 子句设置为最初等于该值,然后动态更改:

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))

虽然这可行,但感觉确实是一种不必要的解决方法,我想看看是否有人知道实现相同结果的更好方法。

【问题讨论】:

    标签: javascript firebase google-cloud-firestore


    【解决方案1】:

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

    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);
    

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

    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);
    

    【讨论】:

    • 两者都工作得很好,非常感谢您的帮助。有条件地将子句推送到查询中也是一种非常优雅且通用的解决方案。
    猜你喜欢
    • 2015-09-29
    • 2018-06-10
    • 2015-07-07
    • 1970-01-01
    • 2017-07-19
    • 2019-02-09
    • 2012-05-06
    相关资源
    最近更新 更多