如何在DocumentDb

时间:2015-12-10 23:14:58

标签: azure azure-cosmosdb

我需要找到每个人最后一次登录的记录。这适用于T-SQL

SELECT *
FROM
(
  SELECT lh.*, ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY DateCreated DESC) AS RowNumber
  FROM LoginHistory lh
) lhp
where lhp.RowNumber = 1

但是由于DocumentDb减少feature set,我无法弄清楚如何处理这个问题。

我认为这需要作为存储过程来解决,但我无法想象如何构建它。循环多个异步调用? (不确定如何做到这一点。)下载所有记录并使用JS过滤它们?

我该如何翻译?

更新:示例输出

PARTITION BY类似于GROUP BY,但它不是聚合结果,而是将记录视为一种范围。所以

  SELECT lh.*, ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY DateCreated DESC) AS RowNumber
  FROM LoginHistory lh

会返回类似

的内容
UserId    DateCreated            RowNumber
1         2015-12-10 22:44:03    1
1         2015-12-10 13:35:12    2
1         2015-12-09 18:52:25    3
2         2015-12-10 20:53:13    1
2         2015-12-10 08:12:41    2

它基本上说,“对于给定的UserId,按DateCreated命令这些记录。”

然后我只在外部查询中选择RowNumber = 1,我有每个用户的最新记录。

我的问题使用了SQL 2015+语法,但也可以使用pre-SQL 2005语法,这可以通过类似this的方式完成:

Select Date, User, Status, Notes 
from [SOMETABLE]
inner join 
(
    Select max(Date) as LatestDate, [User]
    from [SOMETABLE]
    Group by User
) SubMax 
on [SOMETABLE].Date = SubMax.LatestDate
and [SOMETABLE].User = SubMax.User 

不幸的是,DocumentDb也不支持GroupBy。

1 个答案:

答案 0 :(得分:1)

看起来您想要给定UserId的最新值。我可以想到三种替代方法,你建议第二种:

  1. 将所有内容提取回客户端并提取您想要的行。可能是带宽占用并且存在延迟问题,具体取决于数据的大小。

  2. 编写存储过程。如果这是一项您想要做很多事情并且性能至关重要的操作,那么您可能希望采用这种方法。我能够快速调整我的countDocuments sproc来创建你想要的sproc。您可以找到它here(更新:已添加tests并修复了我第一次发布时的错误)。如果您使用的是.NET,则需要预编译该sproc(用CoffeeScript编写)并将其发送到您的服务器。如果你在node.js上,我建议使用documentdb-utils.loadSprocs来加载特定目录中的所有sprocs。 loadSprocs负责编译,甚至允许您通过实现require()支持来模块化和使用您的sprocs中的npm包。

  3. 如果您希望进行其他聚合或分区,那么我建议使用更通用的解决方案documentdb-lumenize,它是在DocumentDB中的存储过程中运行的聚合“库”。使用配置调用存储过程以指定要执行的“聚合”(或分区)。本答案的其余部分是关于如何使用documentdb-lumenize执行此操作的说明。

  4. firstValue(如果您使用ORDER BY DESC)或lastValue(如果您使用默认ASC)聚合函数是您想要的。

    假设你使用的是node.js / CoffeeScript,我会给出答案,但你可以使用JavaScript和/或.NET。无论你喜欢什么,我都可以为你做一个完整的例子。请告诉我。

    第一步是您的查询:

    filterQuery = "SELECT c.ValueToReturn FROM c ORDER BY c.DateCreated"
    

    接下来,您将定义您希望“分区”

    的字段
    dimensions = [{field: "UserId"}]
    

    然后,您需要定义“指标”。

    metrics = [{field: 'ValueToReturn', f: "lastValue", as: "Last Value"}]
    

    最后,将所有内容捆绑到配置对象

    cubeConfig = {dimensions, metrics}
    config = {cubeConfig, filterQuery}
    

    然后,在调用“cube”存储过程时,将config作为唯一参数发送。有关如何将多维数据集添加到集合并执行它的示例,请参阅documentdb-lumenize docs(提供了CoffeeScript / JavaScript / .NET示例)。

    我有一个基于浏览器的Lumenize实现,它允许我给你一个JSFiddle working example。唯一的区别是我没有为浏览器配置指定filterQuery。由于documentdb-lumenize在DocumentDB中工作,因此需要这些基于浏览器不需要的额外信息。它与上面的示例略有不同,因为我坚持使用我刚剪切和粘贴的示例数据中的DESC排序顺序。你想要的那个是“firstValue”。如果排序顺序是ASC,那么你需要“lastValue”,这就是我在上面显示的内容。

    注意,上面的例子只返回一个字段(此处显示为“ValueToReturn”。如果你想要更多,你需要确保它们在你的SELECT子句中(或者只是说“*”)您需要为指标表中的每个字段添加一行。您可以通过编程方式构建指标表,即使您需要50个字段,也只需要几行代码。如果您需要CoffeeScript / JavaScript,请告诉我们。如何以编程方式执行此操作的示例。