首页 > 解决方案 > CosmosDB 计数使用 OrderBy 多个条件

问题描述

我正在使用 Azure CosmosDB,模型包含 Id 和 creationTime 属性。我想做的是在时间间隔内计算条目。我查看了如何使用 LINQ 实现它,但找不到解决方案。我使用的不是SQL。这是我尝试过的:

SELECT VALUE COUNT(1) 
FROM root WHERE (root["DeviceId"] = "myId") 
GROUP BY (root["creationTime"] >= 50 and root["creationTime"] < 60),
(root["creationTime"] >= 40 and root["creationTime"] < 50),
(root["creationTime"] >= 30 and root["creationTime"] < 40),
(root["creationTime"] >= 20 and root["creationTime"] < 30)

请记住,我显示的值仅用于显示目的。正确的结果是具有计数值的数组,例如 [5,0,3,6] 这意味着 ">=50 和 < 60" = 5,">=40 和 < 50" = 0,">=30 和 < 40 " = 3,">=20 和 < 30" = 6,

查询的问题是:

  1. 结果的顺序与查询不匹配,我得到 [3,6,5]
  2. 如果计数为 0,则被解雇
  3. 如果范围没有涵盖所有计数,我也会得到差异。假设数据库包含以下范围:从 5 到 55,因为我从 20 到 60 查询,因此我也得到从 5 到 19 的范围。将所有计数相加将得出总数。

有没有更好的方法来实现这一点,而不是迭代每个间隔然后计算条目数。

谢谢你的帮助。

标签: c#sqllinqazure-cosmosdb

解决方案


如果您正在执行相同分区查询..

..然后您可以通过包含范围描述符来select解决问题(假设实际谓词将更复杂,并且 mod 或函数或其他此类技巧与手头的问题无关),a la:

SELECT 
    (root.creationTime >= 50 and root.creationTime < 60) as V50To60,
    (root.creationTime >= 40 and root.creationTime < 50) as V40To50,
    (root.creationTime >= 30 and root.creationTime < 40) as V30To40,
    (root.creationTime >= 20 and root.creationTime < 30) as V20To30,
    COUNT(1) as total
FROM root 
WHERE root.Id = "myId" 
GROUP BY 
    (root.creationTime >= 50 and root.creationTime < 60),
    (root.creationTime >= 40 and root.creationTime < 50),
    (root.creationTime >= 30 and root.creationTime < 40),
    (root.creationTime >= 20 and root.creationTime < 30)

这样,客户可以根据需要对结果进行排序并确定任何缺失的组。请注意 CosmosDB 不支持order by查询group by(目前),因此您必须在客户端中执行此操作。

如果这是一个跨分区查询..

..那么您在输出中只能有一个VALUE聚合,这意味着您无法从查询中获取组描述符信息。此外,CosmosDB 不支持不相关的联接,所以我倾向于认为也不存在任何魔术联接技巧。即使有,我怀疑它是否漂亮且可维护。

所以,我猜你被迫做多个查询,每个范围一个,并在客户端组合结果。这很可能是简单而有效的(只要您将其包含在索引中),尽管不同的查询不会及时描述同一时刻。

如果您真的-真的需要来自同一时间点的总计,那么您可能需要保留一个索引文档来跟踪范围总计(即使用更改提要)并查询该索引文档。


推荐阅读