【问题标题】:Firestore one range query with order by on different fieldFirestore 一个范围查询,按不同字段排序
【发布时间】:2020-03-26 16:46:58
【问题描述】:

我有以下收藏/文档

Location Collection
{
  "geoHash" : "wwscjrm3nu01",
  "timeStamp" : "March 25, 2020 at 1:07:38 PM UTC-4" 
}
{
  "geoHash" : "wwscjrm2wc2h",
  "timeStamp" : "March 25, 2020 at 2:07:38 PM UTC-4" 
}

请用上面的例子替换 GeoHashs#

所以,我试图通过时间戳“DESC”来查询这些 GeoHash 的范围,如下所示

    db.collection('location')
        .where('geoHash', '>=', 'wwkxt4kxmmvk')
        .where('geoHash', '<=', 'wwt4vsn22peq')
        .orderBy('timeStamp', 'DESC')
        .limit(15).get()

没用,请看下面的错误

Error getting documents { Error: 3 INVALID_ARGUMENT: inequality filter property and first sort order must be the same: geoHash and timeStamp
at callErrorFromStatus (/srv/node_modules/@grpc/grpc-js/build/src/call.js:30:26)
at Http2CallStream.call.on (/srv/node_modules/@grpc/grpc-js/build/src/call.js:79:34)
at emitOne (events.js:121:20)
at Http2CallStream.emit (events.js:211:7)
at process.nextTick (/srv/node_modules/@grpc/grpc-js/build/src/call-stream.js:97:22)
at _combinedTickCallback (internal/process/next_tick.js:132:7)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
code: 3,
details: 'inequality filter property and first sort order must be the 
same: geoHash and timeStamp',
metadata: Metadata { internalRepr: Map {}, options: {} } }

如果我每月或每天在此集合中有数千或数百万个文档怎么办!?你们中的任何人都面临这个问题吗?解决这个问题的最佳方法是什么?

更新 0.2

非常感谢您在解决此问题方面的帮助和支持。我已经复制了我最后看到的内容。

目前,我在 Node js 中使用以下查询

       db.collection('locations')
        .where('geoHash', '>=', 'wwkxt4kxmmvk')
        .where('geoHash', '<=', 'wwt4vsn22peq')
        .orderBy('geoHash')
        .orderBy('timeStamp', 'desc')
        .limit(15).get().then(snapshot => {
          if (snapshot.empty) {
            console.log('No matching documents.');
          }
          snapshot.forEach(doc => {
            console.log(doc.data());
          });
        });

期望是过滤 GeoHash > 对 GeoHash 排序 > 按时间戳排序。因此,最终结果假设为有序时间戳,但我看到的是以下内容,

10:08:24.901 AM
   test
    { geoHash: 'wwscjrm3nu01',
      timeStamp: Timestamp { _seconds: 1585227600, _nanoseconds: 0 },
      post: '3' }
10:08:24.900 AM
   test
    { geoHash: 'wwscjrm3nu01',
      timeStamp: Timestamp { _seconds: 1585317000, _nanoseconds: 0 },
      post: '1' }
10:08:24.900 AM
   test
    { geoHash: 'wwscjrm2wc2h',
      timeStamp: Timestamp { _seconds: 1585314000, _nanoseconds: 0 },
      post: '2' }

正如您在上面的输出中看到的,我除了看到基于时间戳的帖子 1 > 2 > 3,但我在上面看到的是帖子 2 > 1 > 3。

【问题讨论】:

  • 您的两个条件似乎都在同一个字段上,因此与您链接的我的答案似乎完全不同。 1) 这个查询有什么问题? 2) 您能否显示无法正常工作的文档的屏幕截图? 3)最后:你能用range.lowerrange.upper 的硬编码值重现并编辑你的问题以显示这些值吗?
  • 谢谢@FrankvanPuffelen,我已经更新了你提出的所有观点的帖子,
  • 在 Firestore 方面,如何计算 geohashes 并不重要。您可以使用硬编码的 geohash 值进行复制,然后在问题中使用这些值吗?这里的目标是排除尽可能多的代码,尽可能多地在您这边造成问题,这样我们就必须考虑更少。
  • 对于错误消息:听起来您需要在where 子句之前添加orderBy("geoHash")。这也意味着您需要定义一个复合索引,但是会出现一条错误消息,其中包含一个直接链接来帮助您。
  • Both ways the results were not ordered by timeStamp 请不要说结果不是,而是显示结果,以及您对结果的期望。请注意,它们将主要由geoHash 订购,之后仅在timeStamp 上订购。这是设计使然,也是 API 要求您添加额外的 orderBy() 的原因之一 - 以便明确排序顺序首先是 geoHash,然后是 timeStamp

标签: javascript firebase dart google-cloud-firestore


【解决方案1】:

所以你的工作查询是:

db.collection('locations')
  .orderBy("geoHash")
  .where('geoHash', '>=', range.lower)
  .where('geoHash', '<=', range.upper)
  .orderBy('timeStamp', 'DESC')
  .limit(15).get()

从我看到的结果来看,您得到的结果是按geoHash 排序的,然后才按timeStamp 排序。所以:如果两个文档具有相同的geoHash 值,它们将按照它们的timeStamp 值的顺序排列。

这是按预期工作的:当您对字段进行范围查询时,您总是首先需要对该字段进行排序。并且由于您首先对该字段进行排序,因此结果会按照该字段的顺序返回。

这是 Firestore 查询模型的固有特性,因此了解更多信息可能会有所帮助。它的性能保证意味着,一旦找到查询的起点,它必须始终能够从数据库中流式传输结果。对未知数量的结果重新排序将无法始终满足该性能保证,因此不支持此操作。

要按时间戳顺序获取结果,您需要在应用程序代码中重新排序。

【讨论】:

  • 弗兰克的好答案!
  • 明白了,谢谢,这里真的是一个简短的问题。您通过在客户端订购它们有什么建议,我猜这对数千或数百万个文档无效,您对解决这个问题有什么建议?我正在考虑使用与函数集成的 Cloud SQL“MySQL”/。
  • 由于您只检索 15 个文档,这应该不是问题。一般来说:您应该只从 Firestore 请求您的用户实际会看到的数据,因此数百万个文档是一个不太可能的数字。当我看到开发人员检索大量文档时,通常是因为他们正在进行客户端聚合。虽然这是一个有效的选择,但它浪费了用户的带宽和您的金钱(因为您正在阅读许多不会显示的文档)。见stackoverflow.com/a/58614687
  • 你是对的!但我的意思是如果用户只想查看今天的帖子并按时间排序等等,而我的查询不能保证所有不同值的降序getHashs by 今天的帖子,它可以带来其他日期的帖子。
  • 是的,没错。这是一个完全独立的问题,但我建议在这里阅读我的解释:stackoverflow.com/questions/55329334/…(令人惊讶的是没有任何支持)
【解决方案2】:

正如您在 public documentation 中看到的那样,您尝试在不同的字段上执行范围过滤和 first orderBy,这在 Firestore 中是无效的。

此外,如果您尝试进行多次订购,请记住您将按第一个 orderBy 排列所有结果,然后,如果有类似的结果,这将按第二个 orderBy 排列(在您的情况下,您将首先按geoHash排列所有结果,然后按geoHash排列,这将按日期排序,但只有这个类似的条目)

【讨论】:

  • 谢谢你,克里斯,我已经在帖子中复制了结果和期望。
  • 好的,我会尽量让我的答案更清楚。根据文档,您尝试执行的操作无效。您对新查询所做的是对所有 geoHash 进行排序,然后,每当您有 2 个或更多类似的 geoHash 时,这对夫妇将按日期排序,而不是整个数组。
  • 查询的实际输出是该特定查询的预期输出,为什么?因为它将您的 geoHash 订购为wwscjrm3nu01 &gt; wwscjrm3nu01 &gt; wwscjrm2wc2h,然后因为您有 2 次 wwscjrm3nu01,所以它只订购了此 geohash 的时间戳为1585317000 &gt; 1585227600。这第二个 orderBy 不会重新排序其他 geoHash。如果您希望所有结果按日期排序,那么您要做的就是按日期而不是按 geoHash 选择结果
  • 我完全了解这里的情况。非常感谢您的解释。
猜你喜欢
  • 2018-09-19
  • 2018-05-12
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2018-04-10
  • 2018-04-14
相关资源
最近更新 更多