【问题标题】:Selecting the latest document for each "Group"为每个“组”选择最新文档
【发布时间】:2020-09-09 06:53:10
【问题描述】:

我正在使用 Azure Cosmos DB SQL API 来尝试实现以下目标;

我们将设备数据存储在一个集合中,并且希望能够有效地检索每个设备序列的最新事件数据,而无需分别对每个设备进行 N 次查询。

SELECT * 
FROM c
WHERE c.serial IN ('V55555555','synap-aim-g1') ORDER BY c.EventEnqueuedUtcTime DESC

我假设我需要使用 Group By - https://docs.microsoft.com/en-us/azure/cosmos-db/sql-query-group-by

任何帮助将不胜感激

粗略的数据示例:

[
    {
        "temperature": 25.22063251827873,
        "humidity": 71.54208429695204,
        "serial": "V55555555",
        "testid": 1,
        "location": {
            "type": "Point",
            "coordinates": [
                30.843687,
                -29.789895
            ]
        },
        "EventProcessedUtcTime": "2020-09-07T12:04:34.5861918Z",
        "PartitionId": 0,
        "EventEnqueuedUtcTime": "2020-09-07T12:04:34.4700000Z",
        "IoTHub": {
            "MessageId": null,
            "CorrelationId": null,
            "ConnectionDeviceId": "V55555555",
            "ConnectionDeviceGenerationId": "637323979596346475",
            "EnqueuedTime": "2020-09-07T12:04:34.0000000"
        },
        "Name": "admin",
        "id": "6dac491e-1f28-450d-bf97-3a15a0efaad8",
        "_rid": "i2UhAI7ofAo3AQAAAAAAAA==",
        "_self": "dbs/i2UhAA==/colls/i2UhAI7ofAo=/docs/i2UhAI7ofAo3AQAAAAAAAA==/",
        "_etag": "\"430131c1-0000-0100-0000-5f5621d80000\"",
        "_attachments": "attachments/",
        "_ts": 1599480280
    }
]

更新: 因此,执行以下操作会返回正确的数据,但遗憾的是您只能返回组内的数据或聚合函数(即不能选择 *)

SELECT c.serial, MAX(c.EventProcessedUtcTime)
FROM c
WHERE c.serial IN ('V55555555','synap-aim-g1') 
GROUP BY c.serial

[
    {
        "serial": "synap-aim-g1",
        "$1": "2020-09-09T06:29:42.6812629Z"
    },
    {
        "serial": "V55555555",
        "$1": "2020-09-07T12:04:34.5861918Z"
    }
]

【问题讨论】:

  • 根据“每个设备序列的最新事件数据”,您的意思是说您可以拥有多个文档,比如说“V55555555”具有不同的“EventProcessedUtcTime”,我们需要选择其中最新的一个,并且每个设备都必须这样做吗?
  • 这是正确的@AnuragSharma-MSFT,每个设备序列(分区)我们将拥有无限的文档。我想有效地获取最新的文档(按您正确说明的 IoT 中心时间)
  • 恐怕没有直接的方法可以使用 cosmos db 中的查询来实现它。但是,您可以参考以下链接了解同一主题。如果您使用任何 sdk,这将有助于实现所需的功能:docs.microsoft.com/en-us/answers/questions/38454/index.html
  • 好吧,我这么想。谢谢!
  • 嗨@David,非常感谢 AnuragSharma-MSFT 的帮助!我们很高兴您解决了它。更新应该作为答案发布,我只是帮你发布。您可以接受它作为答案。这对其他社区成员可能是有益的。谢谢。

标签: sql group-by azure-cosmosdb azure-cosmosdb-sqlapi


【解决方案1】:

感谢@AnuragSharma-MSFT 的帮助:

很高兴您以这种方式解决了这个问题,感谢您分享更新:

因此,执行以下操作会返回正确的数据,但遗憾的是,您只能返回 group by 或聚合函数中的数据(即不能选择 *)

SELECT c.serial, MAX(c.EventProcessedUtcTime)
FROM c
WHERE c.serial IN ('V55555555','synap-aim-g1') 
GROUP BY c.serial

[
    {
        "serial": "synap-aim-g1",
        "$1": "2020-09-09T06:29:42.6812629Z"
    },
    {
        "serial": "V55555555",
        "$1": "2020-09-07T12:04:34.5861918Z"
    }
]

【讨论】:

  • 非常感谢,我会标记答案。只是一个关于尽可能并行执行此操作的问题。我会像parallel.foreach一样逃脱吗?是否有更智能(RU)的方式来并行执行这些 N 个查询(使用串行..分区键和 Id)?这些查询当然是轻量级的,但只是想知道是否有一种干净/正确的方法可以通过 cosmosDbClient.ReadDocumentsByQueryAsync() 处理这些 N 个查询
【解决方案2】:

如果问题真的是关于这种特定查询场景的有效方法,我们可以在查询语言本身不能提供有效解决方案的情况下考虑非规范化。 partitioning and modeling 上的本指南有一个有关获取 Feed 中最新项目的相关部分。

我们只需要获取最近的 100 个帖子,而不需要 对整个数据集进行分页。

所以为了优化最后一个请求,我们引入了第三个容器来 我们的设计,完全致力于满足这一要求。我们去规范化 我们的帖子到那个新的提要容器。

按照这种方法,您可以创建一个专用于“最新”查询的“Feed”或“LatestEvent”容器,该容器使用设备序列号为id,并具有单个分区键以保证只有一个每个设备的(最新)事件项,并且可以通过设备序列号获取或使用简单查询以尽可能低的成本列出:

SELECT *
FROM c
WHERE c.serial IN ('V55555555','synap-aim-g1')

更改提要可用于upsert 最新事件,以便在“LatestEvent”容器中创建/覆盖最新事件,因为它的源项是在主中创建的。

【讨论】:

  • 哦,当然!从来没有想过这个!非常感谢。今天将实施。太棒了!
猜你喜欢
  • 2017-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2021-06-18
  • 2021-02-25
相关资源
最近更新 更多