DocumentDB - Mô hình hóa dữ liệu

Mặc dù cơ sở dữ liệu không có lược đồ, như DocumentDB, giúp bạn dễ dàng nắm bắt các thay đổi đối với mô hình dữ liệu của mình, nhưng bạn vẫn nên dành một chút thời gian để suy nghĩ về dữ liệu của mình.

  • Bạn có rất nhiều lựa chọn. Đương nhiên, bạn có thể chỉ làm việc với đồ thị đối tượng JSON hoặc thậm chí các chuỗi thô của văn bản JSON, nhưng bạn cũng có thể sử dụng các đối tượng động cho phép bạn liên kết với các thuộc tính trong thời gian chạy mà không cần xác định lớp tại thời điểm biên dịch.

  • Bạn cũng có thể làm việc với các đối tượng C # thực hoặc các Đối tượng như chúng được gọi, có thể là các lớp miền doanh nghiệp của bạn.

Các mối quan hệ

Chúng ta hãy xem cấu trúc phân cấp của tài liệu. Nó có một số thuộc tính cấp cao nhất như id bắt buộc, cũng như lastName và isRegistered, nhưng nó cũng có các thuộc tính lồng nhau.

{ 
   "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 
}
  • Ví dụ: thuộc tính cha mẹ được cung cấp dưới dạng mảng JSON như được biểu thị bằng dấu ngoặc vuông.

  • Chúng tôi cũng có một mảng khác dành cho trẻ em, mặc dù chỉ có một mảng con trong mảng trong ví dụ này. Vì vậy, đây là cách bạn lập mô hình tương đương với các mối quan hệ một-nhiều trong một tài liệu.

  • Bạn chỉ cần sử dụng các mảng trong đó mỗi phần tử trong mảng có thể là một giá trị đơn giản hoặc một đối tượng phức tạp khác, thậm chí là một mảng khác.

  • Vì vậy, một gia đình có thể có nhiều cha mẹ và nhiều con và nếu bạn nhìn vào các đối tượng con, chúng có thuộc tính vật nuôi, bản thân nó là một mảng lồng nhau cho mối quan hệ một-nhiều giữa trẻ em và vật nuôi.

  • Đối với thuộc tính vị trí, chúng tôi đang kết hợp ba thuộc tính có liên quan, tiểu bang, quận và thành phố vào một đối tượng.

  • Nhúng một đối tượng theo cách này thay vì nhúng một mảng đối tượng tương tự như có mối quan hệ một-một giữa hai hàng trong các bảng riêng biệt trong cơ sở dữ liệu quan hệ.

Nhúng dữ liệu

Khi bạn bắt đầu lập mô hình dữ liệu trong kho lưu trữ tài liệu, chẳng hạn như DocumentDB, hãy cố gắng coi các thực thể của bạn là tài liệu độc lập được đại diện trong JSON. Khi làm việc với cơ sở dữ liệu quan hệ, chúng tôi luôn chuẩn hóa dữ liệu.

  • Bình thường hóa dữ liệu của bạn thường bao gồm việc lấy một thực thể, chẳng hạn như khách hàng và chia nó thành các phần dữ liệu kín đáo, như chi tiết liên hệ và địa chỉ.

  • Để đọc một khách hàng, với tất cả các chi tiết và địa chỉ liên hệ của họ, bạn cần sử dụng JOINS để tổng hợp dữ liệu của mình một cách hiệu quả tại thời điểm chạy.

Bây giờ chúng ta hãy xem cách chúng ta sẽ lập mô hình dữ liệu giống như một thực thể độc lập trong cơ sở dữ liệu tài liệu.

{
   "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} 
   ]
}

Như bạn có thể thấy rằng chúng tôi đã không chuẩn hóa hồ sơ khách hàng trong đó tất cả thông tin của khách hàng được nhúng vào một tài liệu JSON duy nhất.

Trong NoSQL, chúng tôi có một lược đồ miễn phí, vì vậy bạn cũng có thể thêm chi tiết liên hệ và địa chỉ ở định dạng khác nhau. Trong NoSQL, bạn có thể truy xuất bản ghi khách hàng từ cơ sở dữ liệu chỉ trong một thao tác đọc. Tương tự, cập nhật một bản ghi cũng là một thao tác ghi duy nhất.

Sau đây là các bước để tạo tài liệu bằng .Net SDK.

Step 1- Khởi tạo DocumentClient. Sau đó, chúng tôi sẽ truy vấn cơ sở dữ liệu myfirstdb và cũng truy vấn cho bộ sưu tập MyCollection, bộ sưu tập mà chúng tôi lưu trữ trong bộ sưu tập biến riêng này để nó có thể truy cập được trong toàn bộ lớp.

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); 
   }

}

Step 2 - Tạo một số tài liệu trong tác vụ 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(); 
}

Tài liệu đầu tiên sẽ được tạo từ đối tượng động này. Điều này có thể trông giống như JSON, nhưng tất nhiên là không. Đây là mã C # và chúng tôi đang tạo một đối tượng .NET thực, nhưng không có định nghĩa lớp. Thay vào đó, các thuộc tính được suy ra từ cách khởi tạo đối tượng. Bạn cũng có thể nhận thấy rằng chúng tôi chưa cung cấp thuộc tính Id cho tài liệu này.

Step 3 - Bây giờ chúng ta hãy xem xét CreateDocument và nó trông giống như mẫu mà chúng ta đã thấy để tạo cơ sở dữ liệu và bộ sưu tập.

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; 
}

Step 4- Lần này, chúng tôi gọi CreateDocumentAsync chỉ định SelfLink của bộ sưu tập mà chúng tôi muốn thêm tài liệu vào. Chúng tôi nhận được phản hồi có thuộc tính tài nguyên, trong trường hợp này, đại diện cho tài liệu mới với các thuộc tính do hệ thống tạo ra.

Trong tác vụ Tạo Tài liệu sau, chúng tôi đã tạo ba tài liệu.

  • Trong tài liệu đầu tiên, đối tượng Document là một lớp được xác định trong SDK kế thừa từ tài nguyên và vì vậy nó có tất cả các thuộc tính tài nguyên chung, nhưng nó cũng bao gồm các thuộc tính động xác định chính tài liệu không có lược đồ.

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(); 
}
  • Tài liệu thứ hai này chỉ hoạt động với một chuỗi JSON thô. Bây giờ chúng ta bước vào quá tải cho CreateDocument sử dụng JavaScriptSerializer để hủy tuần tự hóa chuỗi thành một đối tượng, sau đó nó chuyển sang cùng một phương thức CreateDocument mà chúng ta đã sử dụng để tạo tài liệu đầu tiên.

  • Trong tài liệu thứ ba, chúng tôi đã sử dụng đối tượng C # Khách hàng được định nghĩa trong ứng dụng của chúng tôi.

Hãy xem khách hàng này, nó có thuộc tính Id và địa chỉ trong đó địa chỉ là một đối tượng lồng nhau với các thuộc tính riêng của nó bao gồm vị trí, đây là một đối tượng lồng nhau khác.

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; } 
   } 
}

Chúng tôi cũng có các thuộc tính thuộc tính JSON vì chúng tôi muốn duy trì các quy ước phù hợp ở cả hai bên của hàng rào.

Vì vậy, tôi chỉ tạo đối tượng Khách hàng mới của mình cùng với các đối tượng con lồng nhau của nó và gọi vào CreateDocument một lần nữa. Mặc dù đối tượng khách hàng của chúng tôi có thuộc tính Id, nhưng chúng tôi không cung cấp giá trị cho nó và vì vậy DocumentDB đã tạo một thuộc tính dựa trên GUID, giống như nó đã làm cho hai tài liệu trước.

Khi đoạn mã trên được biên dịch và thực thi, bạn sẽ nhận được kết quả sau.

**** 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