【问题标题】:Firestore query order on field with filter on a different field字段上的 Firestore 查询顺序与不同字段上的过滤器
【发布时间】:2019-02-24 08:55:58
【问题描述】:

我在 google Cloud Firestore 中遇到查询条件问题。

任何人都可以帮助我。

下面是我获取第一个以 HA_ 开头并按 ID DESC 排序的文档的代码

public Article getLastArticleProvider() {
    ApiFuture<QuerySnapshot> query = firebaseDB.getTblArticles()
            .whereGreaterThanOrEqualTo("articleId", "HA_")
            .orderBy("id", Query.Direction.DESCENDING)
            .limit(1)
            .get();

    QuerySnapshot snapshotApiFuture;
    Article article = null;

    try {
        snapshotApiFuture = query.get();
        List<QueryDocumentSnapshot> documents = snapshotApiFuture.getDocuments();
        for (QueryDocumentSnapshot document : documents) {
            article = document.toObject(Article.class);
        }
    } catch (InterruptedException | ExecutionException e) {
        return null;
    }
    return article;
}

我想获取 articleId 以“HA_”或“XE_”开头的文章的最后一个 id

上图的例子:

  • if(articleId start with "HA_") => 返回 id 为 831 的对象
  • if(articleId start with "XE_") => 返回 id 为 833 的对象

现在我得到一个错误

java.util.concurrent.ExecutionException: com.google.api.gax.rpc.InvalidArgumentException: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: 不等式过滤器属性和第一排序顺序必须相同:articleId 和 id

【问题讨论】:

    标签: java firebase google-cloud-firestore


    【解决方案1】:

    TL;DR

    在您的不等式过滤器属性之后添加一个虚拟订单,并更改您的查询优先级以满足您的需求。

    我在 javascript 上遇到了同样的问题,但我相信这也是一个 java 解决方案。

    完整解决方案:

    当我运行查询时:

    module.exports.getLastGroupChat = async function (groupId) {
        let colRef = db.collection('messages')
        colRef = colRef.where('groupId', '==', groupId)
        colRef = colRef.where('userId', '!=', '')
        colRef = colRef.orderBy('timestamp', 'desc').limit(1)
        const doc = await colRef.get()
        return doc
    

    }

    并收到:

    不等式过滤器属性和第一排序顺序必须相同: userId 和时间戳

    为了解决这个问题,首先,我必须在我的不等式过滤器之后添加一个具有相同不等式属性的排序顺序。

    此外,我必须更改查询优先级以实现不等式属性的虚拟排序顺序。

    注意:您可以在同一个查询上运行where -&gt; order -&gt; where -&gt; order

    module.exports.getLastGroupChat = async function (groupId) {
        let colRef = db.collection('messages')
        colRef = colRef.where('userId', '!=', '')
        colRef = colRef.orderBy('userId', 'desc')
        colRef = colRef.where('groupId', '==', groupId)
        colRef = colRef.orderBy('timestamp', 'desc').limit(1)
        const doc = await colRef.get()
        return doc
    }
    

    该查询在我的本地调试 Firestore 上运行良好。将您的更改推送到您的 firebase 云函数并触发您的函数。查看您的函数日志,您可能会遇到索引错误。

    查询需要索引。你可以在这里创建它:https://console.firebase.google.com/v1/r/project..

    确保您进入链接并建立索引。大约需要五到十分钟才能生效。然后再次运行你的功能,一切都应该很好。

    玩得开心! :)

    【讨论】:

    • 我在 Android 上尝试了您的解决方案,但具有不同字段的双 where 子句不起作用。你能再检查一下吗?我认为它适用于您的情况,因为您使用的是“==”运算符错误:所有具有不等式(notEqualTo、notIn、lessThan、lessThanOrEqualTo、greaterThan 或 greaterThanOrEqualTo)的过滤器必须位于同一字段上。 .whereGreaterThanOrEqualTo("current_date", timestamp) .orderBy("current_date", Query.Direction.DESCENDING) .whereNotEqualTo(country, 0) .orderBy(country)
    • 有几个(但很重要的)firestore 查询限制。您可以在以下文档firebase.google.com/docs/firestore/query-data/queries 中查看所有这些内容。在您遇到复合查询时使用它。
    • 在您的情况下,您在同一查询中的不同字段上组合不等式过滤器,Firestore 不支持。我真的建议您阅读我给您的文档,它将帮助您了解 Firestore 查询限制,并希望找到适合您情况的解决方案。
    • 我昨天刚读过,现在很遗憾地搬回 MySQL
    • Firestore 有很多限制,导致查询非常昂贵且效率低下。 Google 远远落后于其他云数据库,并且仅在创建小型虚拟应用以投放到 playStore 时才有用。
    【解决方案2】:

    正如以下错误所说:

    不等式过滤属性和第一排序顺序必须相同:articleId 和 id

    因此,您不能同时使用不同的属性过滤元素并对它们进行排序,在您的情况下为 articleIdid

    official documentation中还有一个如何做到的例子:

    • 不同字段上的范围过滤器和一阶排序

       citiesRef.whereGreaterThan("population", 100000).orderBy("country"); //Invalid
      

    所以要解决这个问题,你应该对同一个文档属性进行过滤和排序。

    【讨论】:

    • 您有什么建议吗?
    • 我不确定我是否理解您的问题。建议不要对同一属性进行过滤和排序,因为这是不可能的,对吧?
    • 对不起我的英语,但我想要一个类似 sql 查询的结果:Select * from article where articleId LIKE '%HA_%' order by id DESC limit 1
    • 不幸的是,Firestore 文档路径中没有通配符。所以这样的查询不存在。您唯一的选择是使用 whereGreatedThan 和 whereLessThan 方法。
    【解决方案3】:

    也许自从提出这个问题以来,firebase 已经改变了一些事情。

    答案是你可以对不同的字段进行过滤和排序。

    您可以链接 orderby 和过滤器,但是,如果您先过滤,则必须先按该过滤器排序,然后才能按任何其他字段排序。 例如

    citiesRef.where('population', '>', 2500000).orderBy('population').orderBy('country');
    

    在他们的文档中。 https://firebase.google.com/docs/firestore/query-data/order-limit-data#order_and_limit_data

    However, if you have a filter with a range comparison (<, <=, >, >=), your first ordering must be on the same field, see the list of orderBy() limitations below.
    

    您可以链接不同字段的 orderBys,我只是在我的一个查询中做到了。 (第一次运行可能会报错,要求创建索引,甚至还有创建索引的链接)

    await db.collection('daily_equipments').where('date', '<', tomorrow._d).where('date', '>=', date).orderBy('date').orderBy('order','asc').get();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-21
      • 2021-10-21
      • 2013-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-04-08
      • 1970-01-01
      • 2020-04-09
      相关资源
      最近更新 更多