Azure Cosmos DB for NoSQL で日付を扱う

適用対象: NoSQL

Azure Cosmos DB for NoSQL は、ネイティブの JSON データ モデルを通して、スキーマの柔軟性とリッチなインデックス機能を提供します。 データベース、コンテナー、ドキュメント、ストアド プロシージャを含むすべての Azure Cosmos DB リソースは、JSON ドキュメントとしてモデル化されて保存されます。 ポータブルであることが求められる JSON (および Azure Cosmos DB) では、少数の基本的な型 (String、Number、Boolean、Array、Object、Null) しかサポートされません。 しかし、JSON は柔軟性が高いため、開発者およびフレームワークは、これらのプリミティブ型を使用したり、オブジェクトまたは配列として構成したりすることにより、より複雑な型を表現できます。

基本の型の他に、多くのアプリケーションでは日付や時刻の情報を表す DateTime 型が必要です。 この記事では、開発者が、.NET SDK を使用して Azure Cosmos DB で日付の格納、取得、クエリを行う方法を説明します。

DateTimes の格納

Azure Cosmos DB は、string、number、boolean、null、array、object などの JSON 型をサポートしています。 これは直接 DateTime 型をサポートしていません。 現時点では、NoSQL 用 API では日付のローカライズはサポートされていません。 そのため、日付と時刻の情報を文字列として保存する必要があります。 日付と時刻の文字列に推奨される形式は yyyy-MM-ddTHH:mm:ss.fffffffZ であり、これは ISO 8601 UTC 標準に準拠しています。 Azure Cosmos DB においてはすべての日付を UTC として保存することをお勧めします。 日付文字列をこの形式に変換すると、日付を辞書式で並べ替えることができます。 UTC 以外の日付が格納されている場合は、クライアント側でロジックを処理する必要があります。 ローカルの日付と時刻を UTC に変換するには、オフセットが JSON のプロパティとして認識/保存されている必要があります。クライアントはこのオフセットを使用して UTC の日付と時刻の値を計算できます。

日付と時刻文字列をフィルターとして使用する範囲クエリは、日付と時刻文字列がすべて UTC である場合にのみサポートされています。 GetCurrentDateTime システム関数は、yyyy-MM-ddTHH:mm:ss.fffffffZ の形式で現在の UTC の日付と時刻の ISO 8601 文字列の値を返します。

ほとんどのアプリケーションは、次に示す理由から、DateTime の既定の文字列表現を使用している可能性があります。

  • 文字列は比較することができ、DateTime 値は文字列に変換されるとき、その相対的な順序が維持されます。
  • この方法では、JSON 変換のためのカスタム コードまたは属性は必要ありません。
  • JSON に格納されている日付を人間が判読できます。
  • この方法では、高速クエリ パフォーマンスのためのインデックスを利用できます。

たとえば、次のスニペットは、.NET SDK を使用して 2 つの DateTime プロパティ (ShipDateOrderDate) を含む Order オブジェクトをドキュメントとして保存します。

public class Order
{
    [JsonProperty(PropertyName="id")]
    public string Id { get; set; }
    public DateTime OrderDate { get; set; }
    public DateTime ShipDate { get; set; }
    public double Total { get; set; }
}

await container.CreateItemAsync(
    new Order
    {
        Id = "09152014101",
        OrderDate = DateTime.UtcNow.AddDays(-30),
        ShipDate = DateTime.UtcNow.AddDays(-14),
        Total = 113.39
    });

このドキュメントは、次の構造で保存されます。

{
  "id": "09152014101",
  "OrderDate": "2014-09-15T23:14:25.7251173Z",
  "ShipDate": "2014-09-30T23:14:25.7251173Z",
  "Total": 113.39
}

または、DateTimes を Unix タイムスタンプ (つまり 1970 年 1 月 1 日からの経過秒数を表す数値) として保存することもできます。 Azure Cosmos DB for NoSQL の内部タイムスタンプ (_ts) プロパティは、この方法に従っています。 UnixDateTimeConverter クラスを使用して、日付と時刻を数値としてシリアル化できます。

LINQ での日付と時刻のクエリ実行

.NET SDK は、統合言語クエリ (LINQ) を使用する保存されたデータのクエリ実行を自動的にサポートします。 たとえば、次のスニペットは、3 日以内に出荷された注文をフィルター処理する LINQ クエリです。

IQueryable<Order> orders = container
    .GetItemLinqQueryable<Order>(allowSynchronousQueryExecution: true)
    .Where(o => o.ShipDate >= DateTime.UtcNow.AddDays(-3));

LINQ クエリは次の SQL ステートメントに変換され、Azure Cosmos DB で実行されます。

SELECT
    *
FROM
    root
WHERE
    (root["ShipDate"] >= "2014-09-30T23:14:25.7251173Z")

クエリ言語と LINQ プロバイダーの詳細については、「LINQ to SQL 翻訳」を参照してください。

範囲クエリのための日付と時刻のインデックス作成

クエリは DateTime 値では一般的なものです。 これらのクエリを効率的に実行するには、クエリのフィルターのプロパティにインデックスが定義されている必要があります。

インデックス作成ポリシーの詳細については、「インデックス作成ポリシー」を参照してください。