DocumentDB如何在_TS上查询LINQ?

时间:2016-02-13 21:19:29

标签: c# linq datetime azure azure-cosmosdb

我想在文档上查询更新时间戳_ts,以获取自一段时间以来未发生变异的文档。

当我在azure门户中创建一个选择查询时,它可以工作:

DocRepo.Get(x => x.Timestamp.Ticks < CloseDate.Ticks);

奇数是使用datetime对象创建的Ticks,见下文。

但是当我尝试通过LINQ创建它时,它不会这样做,因为你没有_ts而是将Timestamp作为DateTime对象。当我尝试输入一个完整的DateTime对象来与Timestamp进行比较时,它会崩溃,说它不支持它。所以我试试这个:

SELECT * FROM root WHERE root[\"_ts\"][\"Ticks\"] < 6.35909943137688E+17

这没有结果,当我观察执行的查询时,它将此作为选择查询:

<!DOCTYPE html>
<html>
<head>
  <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
</head>
<body>
<h1>Hi <%= @user.username %></h1>
<p>
 Sie haben folgende Tags ausgewählt:
  <% @user.tag_list.each do |tag| %>
    <%= tag %> <br>
  <% end %>

  <br><br>
  <% @infosall.each do |info| %> #<-- Problem on this line
      <%= info.name %><br>
  <% end %><br>
</p>
</body>
</html>

是否可以在_ts时间戳上查询,或者我必须有一个额外的updatedAt字段来执行此操作,这似乎是多余的。

2 个答案:

答案 0 :(得分:5)

您的查询存在一些问题。在第一个查询中,您将“Ticks”(一千万分之一秒 - see here)与_ts值进行比较,这很可能会返回集合中的所有文档,因为_ts值是POSIX(Unix)时间以秒为单位see here。它们也不是基于同一时代。 Unix值从1,1,1970午夜开始,其中Ticks从午夜开始1,1,0001因此,_ts值总是比Ticks值小得多(更不用提到1969年了!)。您需要将日期转换为Unix时间值。您可以创建一个Extension方法来帮助您执行此操作:

    public static long ToUnixTime(this DateTime date)
    {
        var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        return (long)(date - epoch).TotalSeconds;
    }

至于Linq语句,你不能(不幸的是)将DateTime放入Linq查询中,因为DateTime值不会转换为const(这是你得到的错误)。因此,在这两种情况下,您都无法轻松地比较_ts值或TimeStamp值。

那该怎么办?好吧,在查看DocumentDB SDK时,如果查看TimeStamp的定义,您将看到以下内容:

    // Summary:
    //     Gets the last modified timestamp associated with the resource.
    [JsonConverter(typeof(UnixDateTimeConverter))]
    [JsonProperty(PropertyName = "_ts")]
    public virtual DateTime Timestamp { get; internal set; }

因此,默认情况下,SDK将_ts值转换为DateTime并通过TimeStamp字段公开它。根据DocRepo返回的类型,您可以执行以下几项操作。如果它是默认的Document类型,您可以创建一个新类并从Docment类型继承,如下所示:

public class MyDocument : Document
{
    public long _ts
    {
        get; set;
    }
}

如果它是您自己的自定义类,则只需将_ts字段添加到您的类中。无论哪种方式,如果_ts字段存在,DocumentDB将填充该字段。然后,如果添加ToUnixTime扩展方法,您可以像这样编写Linq查询:

DocRepo.Get(x => x._ts < CloseDate.ToUnixTime());

它可能不是一个优雅的解决方案,有人(希望)可能会提出一个更好的解决方案,但我已经证实它适用于我自己的DocumentDB集合。

希望这有帮助。

答案 1 :(得分:0)

这是我用来将Unix时间戳转换为我们可以在C#中轻松理解的DateTime格式:

  public DateTime TimeStamp
        {            
            get
            {
                return DateTimeOffset.FromUnixTimeSeconds(int.Parse(_ts)).DateTime;
            }
        }

希望这有帮助。