Banco de Dados de Documentos - Modelagem de Dados

Embora os bancos de dados sem esquema, como o Banco de Dados de Documentos, facilitem muito a aceitação de alterações em seu modelo de dados, você ainda deve passar algum tempo pensando em seus dados.

  • Você tem muitas opções. Naturalmente, você pode apenas trabalhar com gráficos de objetos JSON ou até mesmo strings brutas de texto JSON, mas também pode usar objetos dinâmicos que permitem vincular a propriedades em tempo de execução sem definir uma classe em tempo de compilação.

  • Você também pode trabalhar com objetos C # reais, ou Entities, como são chamados, que podem ser suas classes de domínio de negócios.

Relacionamentos

Vamos dar uma olhada na estrutura hierárquica do documento. Ele tem algumas propriedades de nível superior, como o id necessário, bem como lastName e isRegistered, mas também possui propriedades aninhadas.

{ 
   "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 
}
  • Por exemplo, a propriedade Parents é fornecida como uma matriz JSON conforme denotado pelos colchetes.

  • Também temos outro array para filhos, embora haja apenas um filho no array neste exemplo. Portanto, é assim que você modela o equivalente a relacionamentos um-para-muitos em um documento.

  • Você simplesmente usa matrizes onde cada elemento da matriz pode ser um valor simples ou outro objeto complexo, até mesmo outra matriz.

  • Portanto, uma família pode ter vários pais e vários filhos e, se você olhar para os objetos filho, eles têm a propriedade de um animal de estimação que é uma matriz aninhada para um relacionamento um para muitos entre crianças e animais de estimação.

  • Para a propriedade location, estamos combinando três propriedades relacionadas, o estado, o condado e a cidade em um objeto.

  • Incorporar um objeto dessa maneira, em vez de incorporar uma matriz de objetos, é semelhante a ter um relacionamento um-para-um entre duas linhas em tabelas separadas em um banco de dados relacional.

Incorporando Dados

Ao começar a modelar dados em um armazenamento de documentos, como o Banco de Dados de Documentos, tente tratar suas entidades como documentos autocontidos representados em JSON. Ao trabalhar com bancos de dados relacionais, sempre normalizamos os dados.

  • Normalizar seus dados normalmente envolve pegar uma entidade, como um cliente, e dividi-la em partes discretas de dados, como detalhes de contato e endereços.

  • Para ler um cliente, com todos os seus detalhes de contato e endereços, você precisa usar JOINS para agregar de forma eficaz seus dados em tempo de execução.

Agora, vamos dar uma olhada em como modelaríamos os mesmos dados como uma entidade independente em um banco de dados de documentos.

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

Como você pode ver, desnormalizamos o registro do cliente, onde todas as informações do cliente são incorporadas em um único documento JSON.

No NoSQL, temos um esquema gratuito, para que você também possa adicionar detalhes de contato e endereços em formatos diferentes. No NoSQL, você pode recuperar um registro de cliente do banco de dados em uma única operação de leitura. Da mesma forma, atualizar um registro também é uma única operação de gravação.

A seguir estão as etapas para criar documentos usando .Net SDK.

Step 1- Instancie o DocumentClient. Em seguida, iremos consultar o banco de dados myfirstdb e também consultar a coleção MyCollection, que armazenamos nesta coleção de variáveis ​​privadas para que seja acessível em toda a classe.

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 - Crie alguns documentos na tarefa 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(); 
}

O primeiro documento será gerado a partir deste objeto dinâmico. Isso pode parecer JSON, mas é claro que não é. Este é o código C # e estamos criando um objeto .NET real, mas não há definição de classe. Em vez disso, as propriedades são inferidas da maneira como o objeto é inicializado. Você pode notar também que não fornecemos uma propriedade Id para este documento.

Step 3 - Agora vamos dar uma olhada no CreateDocument e ele se parece com o mesmo padrão que vimos para criar bancos de dados e coleções.

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- Desta vez, chamamos CreateDocumentAsync especificando o SelfLink da coleção à qual queremos adicionar o documento. Recebemos uma resposta com uma propriedade de recurso que, neste caso, representa o novo documento com suas propriedades geradas pelo sistema.

Na tarefa CreateDocuments a seguir, criamos três documentos.

  • No primeiro documento, o objeto Document é uma classe definida no SDK que herda do recurso e, portanto, possui todas as propriedades de recurso comuns, mas também inclui as propriedades dinâmicas que definem o próprio documento sem esquema.

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(); 
}
  • Este segundo documento funciona apenas com uma string JSON bruta. Agora entramos em uma sobrecarga para CreateDocument que usa o JavaScriptSerializer para desserializar a string em um objeto, que então passa para o mesmo método CreateDocument que usamos para criar o primeiro documento.

  • No terceiro documento, usamos o objeto C # Customer que é definido em nossa aplicação.

Vamos dar uma olhada neste cliente, ele tem uma propriedade Id e endereço em que o endereço é um objeto aninhado com suas próprias propriedades, incluindo localização, que é outro objeto aninhado.

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

Também temos atributos de propriedade JSON em vigor porque queremos manter as convenções adequadas em ambos os lados da cerca.

Então, acabo de criar meu objeto New Customer junto com seus objetos filho aninhados e chamo CreateDocument mais uma vez. Embora nosso objeto de cliente tenha uma propriedade Id, não fornecemos um valor para ele e, portanto, o Banco de Dados de Documentos gerou um com base no GUID, assim como fez para os dois documentos anteriores.

Quando o código acima for compilado e executado, você receberá a seguinte saída.

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