【问题标题】:Firestore: Multiple conditional where clausesFirestore:多个条件 where 子句
【发布时间】:2018-06-10 17:49:40
【问题描述】:

例如,我为我的书籍列表设置了动态过滤器,我可以在其中设置特定的颜色、作者和类别。 此过滤器可以一次设置多种颜色和多个类别。

   Book > Red, Blue > Adventure, Detective.

如何有条件地添加“where”?

  firebase
    .firestore()
    .collection("book")
    .where("category", "==", )
    .where("color", "==", )
    .where("author", "==", )

    .orderBy("date")
    .get()
    .then(querySnapshot => {...

【问题讨论】:

    标签: javascript node.js firebase google-cloud-platform google-cloud-firestore


    【解决方案1】:

    正如您在 API 文档中看到的,collection() 方法返回一个 CollectionReference。 CollectionReference 扩展了Query,并且 Query 对象是不可变的。 Query.where()Query.orderBy() 返回新的 Query 对象,这些对象在原始 Query 之上添加操作(保持未修改)。您必须编写代码来记住这些新的 Query 对象,以便您可以继续使用它们进行链接调用。所以,你可以像这样重写你的代码:

    var query = firebase.firestore().collection("book")
    query = query.where(...)
    query = query.where(...)
    query = query.where(...)
    query = query.orderBy(...)
    query.get().then(...)
    

    现在您可以输入条件来确定您想在每个阶段应用哪些过滤器。只需为每个新添加的过滤器重新分配 query

    if (some_condition) {
        query = query.where(...)
    }
    

    【讨论】:

    • 编辑:它有效,当您重新分配query = 时,我错过了... - 这对我不起作用。所有的 where 调用都被简单地忽略了。这仍然对您有用吗?
    • @JimmyKane afs 是什么?你在使用 AngularFire 吗?如果是这样,那么您的所有对象都是不同的。 AF 将所有内容包装到自己的类型中。
    • 需要注意的是,虽然可以查询多个不同属性的where,但仍然不能查询同一属性的多个where。以您的问题为例,查询.where("category", "==", "adventure").where("category", "==", "detective")仍然有no解决方案
    • @pikilon 这只是固执己见的语法。 Typescript 应该允许您重新定义变量,使用let 来定义它们。我知道不建议这样做,因为它可能由于范围问题而导致意外行为。如果您只是想避免警告,@ts-ignore 就可以了。想到的另一件事是将每个新结果推入一个数组:const queries = [firebase.firestore().collection("book")]; queries.push(queries[queries.length - 1].where(...)); queries[queries.length - 1].get().then(...)。或者你可以写一个包装类......选择你的毒药;-)
    • 您现在可以使用 IN 运算符:firebase.google.com/docs/firestore/query-data/queries
    【解决方案2】:

    除了@Doug Stevenson 的回答。当您有多个where 时,有必要像我的情况一样使其更具动态性。

    function readDocuments(collection, options = {}) {
        let {where, orderBy, limit} = options;
        let query = firebase.firestore().collection(collection);
    
        if (where) {
            if (where[0] instanceof Array) {
                // It's an array of array
                for (let w of where) {
                    query = query.where(...w);
                }
            } else {
                query = query.where(...where);
            }
    
        }
    
        if (orderBy) {
            query = query.orderBy(...orderBy);
        }
    
        if (limit) {
            query = query.limit(limit);
        }
    
        return query
                .get()
                .then()
                .catch()
        }
    
    // Usage
    // Multiple where
    let options = {where: [["category", "==", "someCategory"], ["color", "==", "red"], ["author", "==", "Sam"]], orderBy: ["date", "desc"]};
    
    //OR
    // A single where
    let options = {where: ["category", "==", "someCategory"]};
    
    let documents = readDocuments("books", options);
    

    【讨论】:

      【解决方案3】:

      使用 Firebase 版本 9(2022 年 1 月更新):

      您可以使用多个 where 子句过滤数据:

      import { query, collection, where, getDocs } from "firebase/firestore";
      
      const q = query(
        collection(db, "products"),
        where("category", "==", "Computer"),
        where("types", "array-contains", ['Laptop', 'Lenovo', 'Intel']),
        where("price", "<=", 1000),
      );
      
      const docsSnap = await getDocs(q);
          
      docsSnap.forEach((doc) => {
        console.log(doc.data());
      });
      

      【讨论】:

      【解决方案4】:

      Firebase 版本 9

      docs 没有涵盖这一点,但这里是如何将条件 where 子句添加到查询中

      import { collection, query, where } from 'firebase/firestore'
      
      const queryConstraints = []
      if (group != null) queryConstraints.push(where('group', '==', group))
      if (pro != null) queryConstraints.push(where('pro', '==', pro))
      const q = query(collection(db, 'videos'), ...queryConstraints)
      

      这个答案的来源是我最好的朋友 J-E^S^-U-S 的一些直觉猜测和帮助

      【讨论】:

        【解决方案5】:

        例如,有一个数组是这样的

        const conditionList = [
          {
            key: 'anyField',
            operator: '==',
            value: 'any value',
          },
          {
            key: 'anyField',
            operator: '>',
            value: 'any value',
          },
          {
            key: 'anyField',
            operator: '<',
            value: 'any value',
          },
          {
            key: 'anyField',
            operator: '==',
            value: 'any value',
          },
          {
            key: 'anyField',
            operator: '==',
            value: 'any value',
          },
        ]
        

        然后你就可以把你想要设置查询条件的集合放入这个函数中了。

        function* multipleWhere(
          collection,
          conditions = [{ field: '[doc].[field name]', operator: '==', value: '[any value]' }],
        ) {
          const pop = conditions.pop()
          if (pop) {
            yield* multipleWhere(
              collection.where(pop.key, pop.operator, pop.value),
              conditions,
            )
          }
          yield collection
        }
        

        您将获得集合集查询的条件。

        【讨论】:

          【解决方案6】:

          如果你使用的是角火,你可以像这样使用reduce

          const students = [studentID, studentID2,...];
          
          this.afs.collection('classes',
            (ref: any) => students.reduce(
              (r: any, student: any) => r.where(`students.${student}`, '==', true)
              , ref)
          ).valueChanges({ idField: 'id' });
          

          这是一个多标签的例子……

          您可以轻松地为任何非角度框架更改此设置。

          对于 OR 查询(不能使用多个 where 子句完成),请参阅 here

          【讨论】:

            【解决方案7】:
            async yourFunction(){
                const Ref0 = firebase.firestore().collection("your_collection").doc(doc.id)
            
                const Ref1 = appointmentsRef.where('val1', '==',condition1).get();
                const Ref2 = appointmentsRef.where("val2", "!=", condition2).get()
            
                const [snapshot_val1, snapshot_val2] = await Promise.all([Ref1, Ref2]);
            
                
                const val1_Array = snapshot_val1.docs;
                const val2_Array = snapshot_val2.docs;
            
                const globale_val_Array = val1_Array .concat(val2_Array );
            
                return globale_val_Array ;
              }
            
            
            
            /*Call you function*/
            this.checkCurrentAppointment().then(docSnapshot=> {
                  docSnapshot.forEach(doc=> {
                      console.log("Your data with multiple code query:", doc.data());
                  });
                });
            

            【讨论】:

              【解决方案8】:

              请注意,多个WHERE 子句本质上是AND 操作。

              【讨论】:

                猜你喜欢
                • 2015-09-29
                • 2018-08-08
                • 2015-07-07
                • 1970-01-01
                • 2018-07-08
                • 1970-01-01
                • 2019-02-09
                相关资源
                最近更新 更多