8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

如何在 Cloud Firestore 中执行具有逻辑或的复合查询?

Hamelraj 1月前

138 0

来自文档:您还可以链接多个 where() 方法来创建更具体的查询(逻辑 AND)。如何执行 OR 查询?示例:给我所有字段状态为

来自 文档 :

您还可以链接多个 where() 方法来创建更具体的查询(逻辑与)。

我如何执行 OR 查询?示例:

  1. 给我所有字段为 status 文档 的 open OR upcoming
  2. 给我所有包含以下字段的文档 status == open :OR createdAt <= <somedatetime>
帖子版权声明 1、本帖标题:如何在 Cloud Firestore 中执行具有逻辑或的复合查询?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Hamelraj在本站《firebase》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 我有一个类似的问题,现在我正在编辑我的数据架构,以便值是具有有意范围的数字(例如:无访问权限:0,读取访问权限:1,编辑访问权限:2,所有者访问权限 3。然后我可以查询访问字段 isGreaterThan,例如 1)。本质上,我正在考虑利用数字范围中的隐式 OR。

  • OR 不支持,因为服务器很难扩展它(需要保持状态以进行重复数据删除)。解决方法是发出 2 个查询,每个条件一个,然后在客户端进行重复数据删除。


    编辑(2019 年 11 月):

    Cloud Firestore 现在支持 IN 有限类型的查询 OR

    对于上面的例子你可以这样做:

    // Get all documents in 'foo' where status is open or upcmoming
    db.collection('foo').where('status','in',['open','upcoming']).get()
    

    然而,仍然不可能完成 OR 涉及多个字段的一般条件。

  • 我理解答案,但如果我想获取字段状态为 a OR b OR c OR ... 的所有文档(假设为 50 OR)。我是否需要执行 50 个查询并将它们合并?这似乎不是最佳选择?我错了吗?有没有更好的方法来解决这个问题?谢谢。

  • 我还想知道是否有比在客户端上运行 N 个查询和连接更好的解决方案。似乎效率很低。

  • Ysh 1月前 0 只看Ta
    引用 6

    “服务器难以扩展”的说法只不过是 Google 缺乏技能的蹩脚借口。仅仅因为您的名字是“Google”,并不意味着您就自动成为该领域的专家。其他索引服务器确实支持 OR 运算符。

  • 随着 最近添加的 IN 查询 ,Firestore 支持“在同一字段上使用逻辑 OR 的 "

    (1)的一个可能的解决方案是:

    documents.where('status', 'in', ['open', 'upcoming']);
    

    请参阅 Firebase Guides: Query Operators | in and array-contains-any

    OR 上宣布 支持常规 Google I/O 2023 ,因此根据 文档 ,(2) 的解决方案将是:

    query(collection(db, '{collection-name}'), or(
      where('status', '==', 'open'),   
      where('createdAt', '<=', somedatetime),   
    ));
    

    请参阅 GitHub/firebase 中的完整示例: snippets-node: index.js#orQueries .

  • 文档没有说明要从哪里导入?它在 Web 模块化 @firebase/firestore 包中不可用。我希望它与 query、where 等一起存在。

  • @conor909 这里是使用 firebase-admin 包时的代码片段链接:github.com/firebase/snippets-node/blob/…。还将其添加到答案中。

  • 感谢@Kariem,但我正在使用 web 模块化 api firebase/firestore

  • para 1月前 0 只看Ta
    引用 11

    我最终发现或者通过将我的 firebase/firestore 升级到版本 10 - 有点令人困惑,因为文档提到模块化 api 是版本 9

  • Firebase 于 2023 年引入了 OR 子句

    Web 客户端的模块化 Web 示例

    import { or, collection, query, where } from "firebase/firestore";
    
    const q = query(
      collection(db, "collection_name"), 
      or(
        where('status', '==', 'open'),
        where('createdAt', '<=', Timestamp.fromDate(new Date()))
      )
    );
    

    可以 AND OR 子句结合:

    import { and, or, collection, query, where } from "firebase/firestore";
    
    const q = query(
      collection(db, "cities"), 
      and(
        where('state', '==', 'CA'),   
        or(
          where('capital', '==', true),
          where('population', '>=', 1000000)
      )
    ));
    

    Firebase 函数示例

    import { initializeApp } from 'firebase-admin/app';
    import { Filter, getFirestore } from "firebase-admin/firestore";
    
    const firebaseApp = initializeApp({
      // your paramateres
    });
    const firestore = getFirestore(firebaseApp);
    
    const result = await firestore.collection("cities")
      .where(
        Filter.or(
          Filter.where('capital', '==', true),
          Filter.where('population', '>=', 1000000)
        )
      )
      .get();
    
  • 嘿@AdrianBartholomew,对于模块化 Web UI 版本,您可以使用 import { or, collection, query, and, where } from 'firebase/firestore'。

  • 您可以使用 rxjs 合并运算符绑定两个 Observable。这里有一个示例。

    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/observable/merge';
    
    ...
    
    getCombinatedStatus(): Observable<any> {
       return Observable.merge(this.db.collection('foo', ref => ref.where('status','==','open')).valueChanges(),
                               this.db.collection('foo', ref => ref.where('status','==','upcoming')).valueChanges());
    }
    

    然后您可以使用上述方法订阅新的 Observable 更新:

    getCombinatedStatus.subscribe(results => console.log(results);
    

    我希望这能帮助你,来自智利的问候!!

  • 建议也为地位赋予价值。
    前任。

    { name: "a", statusValue = 10, status = 'open' }
    
    { name: "b", statusValue = 20, status = 'upcoming'}
    
    { name: "c", statusValue = 30, status = 'close'}
    

    您可以通过 ref.where('statusValue', '<=', 20) 两者 'a' ,并 'b' 会找到。

    这可以节省您的查询成本和性能。

    顺便说一句,它并不能解决所有情况。

  • 我没有“状态”字段,但有状态相关字段,根据请求将它们更新为 true 或 false,例如

    { name: "a", status_open: true, status_upcoming: false, status_closed: false}
    

    但是,请检查 Firebase Cloud Functions。您可以让函数监听状态更改,更新与状态相关的属性,例如

    { name: "a", status: "open", status_open: true, status_upcoming: false, status_closed: false}
    

    其中一个,你的查询可能只是

    ...where('status_open','==',true)...
    

    希望有帮助。

  • Biju 1月前 0 只看Ta
    引用 17

    这并不能解决所有情况,但是对于 \'enum\' 字段,您可以通过为每个枚举值创建一个单独的布尔字段来模拟 \'OR\' 查询,然后为 where("enum_<value>", "==", false) 每个值

    例如,考虑您的第一个期望查询:

    1. 给我所有字段状态为“打开”或“即将打开”的文件

    您可以通过将 status: string 字段拆分为多个布尔字段(每个枚举值一个)来实现此目的:

    status_open: bool
    status_upcoming: bool
    status_suspended: bool
    status_closed: bool
    

    要执行“状态为开放或即将开放”查询,请执行以下操作:

    where("status_suspended", "==", false).where("status_closed", "==", false)
    

    这是如何工作的?因为它是一个枚举,所以您知道其中一个值必须已 true 分配。因此,如果您可以确定给定条目的所有 其他 值都不匹配,那么通过推断,它必须与您最初寻找的值之一匹配。

    参见

    in <​/code>/ not-in / array-contains-in : https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any

    != https://firebase.googleblog.com/2020/09/cloud-firestore-not-equal-queries.html

  • 我不喜欢每个人都说这是不可能的。

    如果您在模型中创建另一个“hacky”字段来构建复合字段......

    例如,为每个包含所有逻辑或元素的文档创建一个数组

    然后查询.where(\'field\', arrayContains: [...]

  • 我们现在遇到了同样的问题,幸运的是,我们唯一可能的值是 A、B、C、D(4),所以我们必须查询诸如 A||B、A||C、A||B||C、D 等


    几个月前,firebase 支持了一个新的查询, array-contains 所以我们要做的就是创建一个数组,然后对数组中的 OR 值进行预处理

    if (a) {
    array addObject:@"a"
    }
    if (b) {
    array addObject:@"b"
    }
    if (a||b) {
    array addObject:@"a||b"
    }
    etc
    

    我们对所有的 4! 值或者无论有多少组合都执行此操作。

    然后我们可以简单地检查查询 [document arrayContains:@"a||c"] 或我们需要的任何类型的条件。

    因此,如果某个东西仅满足 A 我们的 4 个条件(A、B、C、D)那么它的数组将包含以下文字字符串: @["A", "A||B", "A||C", "A||D", "A||B||C", "A||B||D", "A||C||D", "A||B||C||D"]

    然后对于任何这些 OR 组合,我们都可以搜索 array-contains 我们想要的任何内容(例如 \'A||C\')


    注意:仅当您有少量可能的值需要进行 OR 比较时,这才是一种合理的方法。

    Array-contains 的 更多信息 ,因为它对于 firebase 文档来说比较新

  • 引用 20

    如果字段数量有限,请像上例一样,使用 true 和 false 创建新字段。但是,如果您直到运行时才知道字段是什么,则必须组合查询。

    这是一个标签或示例...

    // the ids of students in class
    const students = [studentID1, studentID2,...];
    
    // get all docs where student.studentID1 = true
    const results = this.afs.collection('classes',
      ref => ref.where(`students.${students[0]}`, '==', true)
    ).valueChanges({ idField: 'id' }).pipe(
      switchMap((r: any) => {
    
        // get all docs where student.studentID2...studentIDX = true
        const docs = students.slice(1).map(
          (student: any) => this.afs.collection('classes',
            ref => ref.where(`students.${student}`, '==', true)
          ).valueChanges({ idField: 'id' })
        );
        return combineLatest(docs).pipe(
    
          // combine results by reducing array
          map((a: any[]) => {
            const g: [] = a.reduce(
              (acc: any[], cur: any) => acc.concat(cur)
            ).concat(r);
    
            // filter out duplicates by 'id' field
            return g.filter(
              (b: any, n: number, a: any[]) => a.findIndex(
                (v: any) => v.id === b.id) === n
            );
          }),
        );
      })
    );
    

    不幸的是,没有其他方法可以组合超过 10 个项目(如果项目少于 10 个,则使用 array-contains-any)。

    另外,没有其他方法可以避免重复读取,因为您不知道搜索将匹配哪些 ID 字段。幸运的是,Firebase 具有良好的缓存功能。

    对于那些喜欢承诺的人来说……

    const p = await results.pipe(take(1)).toPromise();
    

    有关更多信息,请参阅 我写的 这篇文章

    J

返回
作者最近主题: