繁体   English   中英

如何在 Cloud Firestore 中使用逻辑 OR 执行复合查询?

[英]How to perform compound queries with logical OR in Cloud Firestore?

文档

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

如何执行OR查询? 例子:

  1. 给我所有字段statusopenupcoming的文件
  2. 给我所有字段status == opencreatedAt <= <somedatetime>的文档

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条件。

随着最近添加的 IN 查询,Firestore 支持“同一字段上最多 10 个具有逻辑OR 的相等子句”

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

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

请参阅Firebase 指南:查询运算符 | inarray-contains-any

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

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

希望能帮助到你。

您可以使用 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);

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

我们刚才遇到了同样的问题,幸运的是我们的唯一可能的值是 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!都这样做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 docs 来说是新的

这并不能解决所有情况,但对于“枚举”字段,您可以通过为每个枚举值创建一个单独的布尔字段来模拟“或”查询,然后添加一个where("enum_<value>", "==", false)对于不是您想要的“OR”子句的一部分的每个值。

例如,考虑您想要的第一个查询:

  1. 给我字段状态为打开或即将到来的所有文档

您可以通过将status: string字段拆分为多个布尔字段来实现这一点,每个枚举值对应一个:

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

要执行“where status is open orcoming”查询,请执行以下操作:

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

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

也可以看看

in / not-in / array-contains-inhttps : //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

如果您的字段数量有限,请务必像上面的示例一样创建具有 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

或不支持

但是如果你需要,你可以在你的代码中做到

例如:如果我想查询产品 where( Size Equal Xl OR XXL : AND Gender is Male)

productsCollectionRef
                //1* first get query where can firestore handle it
                .whereEqualTo("gender", "Male")
                .addSnapshotListener((queryDocumentSnapshots, e) -> {

                    if (queryDocumentSnapshots == null)
                        return;

                    List<Product> productList = new ArrayList<>();
                    for (DocumentSnapshot snapshot : queryDocumentSnapshots.getDocuments()) {
                        Product product = snapshot.toObject(Product.class);

                        //2* then check your query OR Condition because firestore just support AND Condition
                            if (product.getSize().equals("XL") || product.getSize().equals("XXL"))
                                productList.add(product);
                    }

                    liveData.setValue(productList);

                });

对于 Flutter dart 语言,请使用:

db.collection("projects").where("status", whereIn: ["public", "unlisted", "secret"]);

实际上,我发现 @Dan McGrath 在这里工作的答案是对他的答案的重写:

 private void query() {
        FirebaseFirestore db = FirebaseFirestore.getInstance();
        db.collection("STATUS")
                .whereIn("status", Arrays.asList("open", "upcoming")) // you can add up to 10 different values like : Arrays.asList("open", "upcoming", "Pending", "In Progress", ...)
                .addSnapshotListener(new EventListener<QuerySnapshot>() {
                    @Override
                    public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {

                        for (DocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
// I assume you have a  model class called MyStatus

                            MyStatus status= documentSnapshot.toObject(MyStatus.class);
                            if (status!= null) {
                               //do somthing...!
                            }
                        }
                    }
                });

    }

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM