Documentdb-data-modeling

提供:Dev Guides
移動先:案内検索

DocumentDB-データモデリング

DocumentDBのようなスキーマフリーデータベースを使用すると、データモデルへの変更を非常に簡単に取り入れることができますが、データについて考えるのにしばらく時間をかける必要があります。

  • あなたにはたくさんの選択肢があります。 当然、JSONオブジェクトグラフまたはJSONテキストの生の文字列だけで作業できますが、コンパイル時にクラスを定義せずに実行時にプロパティにバインドできる動的オブジェクトを使用することもできます。
  • また、実際のC#オブジェクト、またはそれらが呼び出されたエンティティ(ビジネスドメインクラス)を操作することもできます。

関係

ドキュメントの階層構造を見てみましょう。 必要なid、lastName、isRegisteredなどのトップレベルプロパティがいくつかありますが、ネストされたプロパティもあります。

{
   "id": "AndersenFamily",
   "lastName": "Andersen",

   "parents": [
      { "firstName": "Thomas", "relationship": "father" },
      { "firstName": "Mary Kay", "relationship": "mother" }
   ],

   "children": [
      {
         "firstName": "Henriette Thaulow",
         "gender": "female",
         "grade": 5,
         "pets": [ { "givenName": "Fluffy", "type": "Rabbit" } ]
      }
   ],

   "location": { "state": "WA", "county": "King", "city": "Seattle"},
   "isRegistered": true
}
  • たとえば、parentsプロパティは、角括弧で示されるJSON配列として提供されます。
  • この例では、配列に子が1つしかない場合でも、子用の別の配列もあります。 これが、ドキュメント内の1対多の関係に相当するものをモデル化する方法です。
  • 単純に配列を使用します。配列内の各要素は、単純な値または別の複雑なオブジェクト、さらに別の配列になります。
  • したがって、1つの家族は複数の親と複数の子を持つことができ、子オブジェクトを見ると、それ自体が子とペットの1対多の関係のネストされた配列であるペットのプロパティを持っています。
  • locationプロパティについては、3つの関連するプロパティ、州、郡、市をオブジェクトに結合しています。
  • オブジェクトの配列を埋め込むのではなく、この方法でオブジェクトを埋め込むことは、リレーショナルデータベースの別々のテーブルにある2つの行の間に1対1の関係を持たせることに似ています。

データを埋め込む

DocumentDBなどのドキュメントストアでデータのモデリングを開始するときは、エンティティをJSONで表される自己完結型ドキュメントとして扱うようにしてください。 リレーショナルデータベースを使用する場合、常にデータを正規化します。

  • データを正規化するには、通常、顧客などのエンティティを取得し、連絡先の詳細や住所などの個別のデータに分割します。
  • 連絡先の詳細と住所をすべて記載した顧客を読むには、JOINSを使用して実行時にデータを効果的に集約する必要があります。

ここで、ドキュメントデータベースの自己完結型エンティティと同じデータをモデル化する方法を見てみましょう。

{
   "id": "1",
   "firstName": "Mark",
   "lastName": "Upston",

   "addresses": [
      {
         "line1": "232 Main Street",
         "line2": "Unit 1",
         "city": "Brooklyn",
         "state": "NY",
         "zip": 11229
      }
   ],

   "contactDetails": [
      {"email": "[email protected]"},
      {"phone": "+1 356 545-86455", "extension": 5555}
   ]
}

ご覧のとおり、顧客のすべての情報が単一のJSONドキュメントに埋め込まれている顧客レコードを非正規化しています。

NoSQLには無料のスキーマがあるため、連絡先の詳細と住所を異なる形式で追加することもできます。 NoSQLでは、1回の読み取り操作でデータベースから顧客レコードを取得できます。 同様に、レコードの更新も単一の書き込み操作です。

以下は、.Net SDKを使用してドキュメントを作成する手順です。

  • ステップ1 *-DocumentClientをインスタンス化します。 次に、myfirstdbデータベースを照会し、MyCollectionコレクションを照会します。MyCollectionコレクションは、このプライベート変数コレクションに格納し、クラス全体でアクセスできるようにします。
private static async Task CreateDocumentClient() {
  //Create a new instance of the DocumentClient

   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
      database = client.CreateDatabaseQuery("SELECT *FROM c WHERE c.id =
         'myfirstdb'").AsEnumerable().First();

      collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
         "SELECT* FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();

      await CreateDocuments(client);
   }

}
  • ステップ2 *-CreateDocumentsタスクでいくつかのドキュメントを作成します。
private async static Task CreateDocuments(DocumentClient client) {
   Console.WriteLine();
   Console.WriteLine("*** *Create Documents* ***");
   Console.WriteLine();

   dynamic document1Definition = new {
      name = "New Customer 1", address = new {
         addressType = "Main Office",
         addressLine1 = "123 Main Street",
         location = new {
            city = "Brooklyn", stateProvinceName = "New York"
         },
         postalCode = "11229", countryRegionName = "United States"
      },
   };

   Document document1 = await CreateDocument(client, document1Definition);
   Console.WriteLine("Created document {0} from dynamic object", document1.Id);
   Console.WriteLine();
}

最初のドキュメントは、この動的オブジェクトから生成されます。 これはJSONのように見えるかもしれませんが、もちろんそうではありません。 これはC#コードであり、実際の.NETオブジェクトを作成していますが、クラス定義はありません。 代わりに、プロパティはオブジェクトの初期化方法から推測されます。 また、このドキュメントのIdプロパティが提供されていないことにも気づくでしょう。

  • ステップ3 *-次に、CreateDocumentを見てみましょう。データベースとコレクションの作成で見たのと同じパターンのように見えます。
private async static Task<Document> CreateDocument(DocumentClient client,
   object documentObject) {
   var result = await client.CreateDocumentAsync(collection.SelfLink, documentObject);

   var document = result.Resource;
   Console.WriteLine("Created new document: {0}\r\n{1}", document.Id, document);

   return result;
}
  • ステップ4 *-今回は、ドキュメントを追加するコレクションのSelfLinkを指定してCreateDocumentAsyncを呼び出します。 この場合、システムによって生成されたプロパティを持つ新しいドキュメントを表すリソースプロパティを持つ応答が返されます。

次のCreateDocumentsタスクでは、3つのドキュメントを作成しました。

  • 最初のドキュメントでは、Documentオブジェクトはリソースから継承するSDKで定義されたクラスであるため、すべての共通リソースプロパティがありますが、スキーマフリードキュメント自体を定義する動的プロパティも含まれています。
private async static Task CreateDocuments(DocumentClient client) {
   Console.WriteLine();
   Console.WriteLine("*** *Create Documents* ***");
   Console.WriteLine();

   dynamic document1Definition = new {
      name = "New Customer 1", address = new {
         addressType = "Main Office",
         addressLine1 = "123 Main Street",
         location = new {
            city = "Brooklyn", stateProvinceName = "New York"
         },
         postalCode = "11229",
         countryRegionName = "United States"
      },
   };

   Document document1 = await CreateDocument(client, document1Definition);
   Console.WriteLine("Created document {0} from dynamic object", document1.Id);
   Console.WriteLine();

   var document2Definition = @" {
      ""name"": ""New Customer 2"",

      ""address"": {
         ""addressType"": ""Main Office"",
         ""addressLine1"": ""123 Main Street"",
         ""location"": {
            ""city"": ""Brooklyn"", ""stateProvinceName"": ""New York""
         },
         ""postalCode"": ""11229"",
         ""countryRegionName"": ""United States""
      }
   }";

   Document document2 = await CreateDocument(client, document2Definition);
   Console.WriteLine("Created document {0} from JSON string", document2.Id);
   Console.WriteLine();

   var document3Definition = new Customer {
      Name = "New Customer 3",

      Address = new Address {
         AddressType = "Main Office",
         AddressLine1 = "123 Main Street",
         Location = new Location {
            City = "Brooklyn", StateProvinceName = "New York"
         },
         PostalCode = "11229",
         CountryRegionName = "United States"
      },
   };

   Document document3 = await CreateDocument(client, document3Definition);
   Console.WriteLine("Created document {0} from typed object", document3.Id);
   Console.WriteLine();
}
  • この2番目のドキュメントは、生のJSON文字列でのみ機能します。 ここで、JavaScriptSerializerを使用して文字列をオブジェクトに逆シリアル化するCreateDocumentのオーバーロードにステップインし、最初のドキュメントの作成に使用したのと同じCreateDocumentメソッドに渡します。
  • 3番目のドキュメントでは、アプリケーションで定義されているC#オブジェクトCustomerを使用しました。

この顧客を見てみましょう。IDとアドレスのプロパティがあります。アドレスは、さらに別のネストされたオブジェクトである場所を含む独自のプロパティを持つネストされたオブジェクトです。

using Newtonsoft.Json;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DocumentDBDemo {

   public class Customer {
      [JsonProperty(PropertyName = "id")]
      public string Id { get; set; }
     //Must be nullable, unless generating unique values for new customers on client
      [JsonProperty(PropertyName = "name")]
      public string Name { get; set; }
      [JsonProperty(PropertyName = "address")]
      public Address Address { get; set; }
   }

   public class Address {
      [JsonProperty(PropertyName = "addressType")]
      public string AddressType { get; set; }

      [JsonProperty(PropertyName = "addressLine1")]
      public string AddressLine1 { get; set; }

      [JsonProperty(PropertyName = "location")]
      public Location Location { get; set; }

      [JsonProperty(PropertyName = "postalCode")]
      public string PostalCode { get; set; }

      [JsonProperty(PropertyName = "countryRegionName")]
      public string CountryRegionName { get; set; }
   }

   public class Location {
      [JsonProperty(PropertyName = "city")]
      public string City { get; set; }

      [JsonProperty(PropertyName = "stateProvinceName")]
      public string StateProvinceName { get; set; }
   }
}

また、フェンスの両側で適切な規則を維持したいため、JSONプロパティ属性も用意されています。

したがって、ネストされた子オブジェクトと共にNew Customerオブジェクトを作成し、CreateDocumentをもう一度呼び出します。 顧客オブジェクトにはIdプロパティがありますが、値を提供しなかったため、DocumentDBは前の2つのドキュメントの場合と同様に、GUIDに基づいて値を生成しました。

上記のコードをコンパイルして実行すると、次の出力が表示されます。

*** *Create Documents* ***
Created new document: 575882f0-236c-4c3d-81b9-d27780206b2c
{
  "name": "New Customer 1",
  "address": {
    "addressType": "Main Office",
    "addressLine1": "123 Main Street",
    "location": {
      "city": "Brooklyn",
      "stateProvinceName": "New York"
    },
    "postalCode": "11229",
    "countryRegionName": "United States"
  },
  "id": "575882f0-236c-4c3d-81b9-d27780206b2c",
  "_rid": "kV5oANVXnwDGPgAAAAAAAA==",
  "_ts": 1450037545,
  "_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDGPgAAAAAAAA==/",
  "_etag": "\"00006fce-0000-0000-0000-566dd1290000\"",
  "_attachments": "attachments/"
}
Created document 575882f0-236c-4c3d-81b9-d27780206b2c from dynamic object
Created new document: 8d7ad239-2148-4fab-901b-17a85d331056
{
  "name": "New Customer 2",
  "address": {
    "addressType": "Main Office",
    "addressLine1": "123 Main Street",
    "location": {
      "city": "Brooklyn",
      "stateProvinceName": "New York"
    },
    "postalCode": "11229",
    "countryRegionName": "United States"
  },
  "id": "8d7ad239-2148-4fab-901b-17a85d331056",
  "_rid": "kV5oANVXnwDHPgAAAAAAAA==",
  "_ts": 1450037545,
  "_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDHPgAAAAAAAA==/",
  "_etag": "\"000070ce-0000-0000-0000-566dd1290000\"",
  "_attachments": "attachments/"
}
Created document 8d7ad239-2148-4fab-901b-17a85d331056 from JSON string
Created new document: 49f399a8-80c9-4844-ac28-cd1dee689968
{
  "id": "49f399a8-80c9-4844-ac28-cd1dee689968",
  "name": "New Customer 3",
  "address": {
    "addressType": "Main Office",
    "addressLine1": "123 Main Street",
    "location": {
      "city": "Brooklyn",
      "stateProvinceName": "New York"
    },
    "postalCode": "11229",
    "countryRegionName": "United States"
  },
  "_rid": "kV5oANVXnwDIPgAAAAAAAA==",
  "_ts": 1450037546,
  "_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDIPgAAAAAAAA==/",
  "_etag": "\"000071ce-0000-0000-0000-566dd12a0000\"",
  "_attachments": "attachments/"
}
Created document 49f399a8-80c9-4844-ac28-cd1dee689968 from typed object