MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Introdução aos tipos de dados do MongoDB


Introdução


Ao usar o MongoDB, você tem a capacidade de ser flexível com a estrutura de seus dados. Você não está preso a manter um determinado esquema no qual todos os seus documentos devem se encaixar. Para qualquer campo em um documento, você pode usar qualquer um dos tipos de dados disponíveis suportado pelo MongoDB. Apesar dessa maneira padrão de trabalhar, você pode impor um esquema JSON no MongoDB para adicionar validação em suas coleções, se desejar. Não entraremos nos detalhes do design do esquema neste guia, mas ele pode afetar a digitação de dados se implementado.

Os tipos de dados especificam um padrão geral para os dados que eles aceitam e armazenam. É fundamental entender quando escolher um determinado tipo de dados em detrimento de outro ao planejar seu banco de dados. O tipo escolhido vai ditar como você pode operar seus dados e como eles são armazenados.


JSON e BSON


Antes de entrar nos detalhes de tipos de dados específicos, é importante entender como o MongoDB armazena dados. O MongoDB e muitos outros bancos de dados NoSQL baseados em documentos usam JSON (JavaScript Object Notation) para representar registros de dados como documentos.

Há muitas vantagens em usar JSON para armazenar dados. Alguns deles sendo:
  • facilidade de ler, aprender e familiaridade entre os desenvolvedores
  • flexibilidade no formato, seja esparso, hierárquico ou profundamente aninhado
  • autodescritivo, que permite que os aplicativos operem facilmente com dados JSON
  • permite o foco em um número mínimo de tipos básicos

JSON suporta todos os tipos de dados básicos como string, número, booleano, etc. O MongoDB na verdade armazena registros de dados como documentos JSON (BSON) codificados em binário. Assim como o JSON, o BSON suporta a incorporação de documentos e matrizes em outros documentos e matrizes. BSON permite tipos de dados adicionais que não estão disponíveis para JSON.


Quais são os tipos de dados no MongoDB?


Antes de entrar em detalhes, vamos ter uma visão ampla de quais tipos de dados são suportados no MongoDB.

O MongoDB suporta uma variedade de tipos de dados adequados para vários tipos de dados simples e complexos. Esses incluem:

Texto
  • String

Numérico
  • 32-Bit Integer
  • 64-Bit Integer
  • Double
  • Decimal128

Data hora
  • Date
  • Timestamp

Outro
  • Object
  • Array
  • Binary Data
  • ObjectId
  • Boolean
  • Null
  • Regular Expression
  • JavaScript
  • Min Key
  • Max Key

No MongoDB, cada tipo BSON tem identificadores de inteiro e string. Abordaremos os mais comuns com mais profundidade ao longo deste guia.


Tipos de string


O tipo string é o tipo de dados MongoDB mais comumente usado. Qualquer valor escrito entre aspas duplas "" em JSON é um valor de string. Qualquer valor que você deseja armazenar como texto será melhor digitado como uma String . As strings BSON são UTF-8 e são representadas no MongoDB como:
        Type         | Number |  Alias   |  ------------------ | ------ | -------- |       String        |    2   | "string" |

Geralmente, os drivers para linguagens de programação serão convertidos do formato de string da linguagem para UTF-8 ao serializar e desserializar o BSON. Isso torna o BSON um método atraente para armazenar caracteres internacionais com facilidade, por exemplo.

Inserindo um documento com uma String tipo de dados será algo assim:
db.mytestcoll.insertOne({first_name: "Alex"}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d15")}

Consultar a coleção retornará o seguinte:
db.mytestcoll.find().pretty(){        _id: ObjectId("614b37296a124db40ae74d15"),         first_name: "Alex"}

Usando o $type operador


Antes de passar para o nosso próximo tipo de dados, é importante saber como você pode digitar o valor antes de fazer qualquer inserção. Usaremos o exemplo anterior para demonstrar usando o $type operador no MongoDB.

Digamos que já faz algum tempo desde que trabalhamos com o mytestcoll coleção de antes. Queremos inserir alguns documentos adicionais na coleção com o first_name campo. Para verificar se usamos String como o tipo de dados armazenado como um valor de first_name originalmente, podemos executar o seguinte usando o alias ou o valor numérico do tipo de dados:
db.mytestcoll.find( { "first_name": { $type: "string" } } )

Ou
db.mytestcoll.find( { "first_name": { $type: 2 } } )

Ambas as consultas retornam uma saída de todos os documentos que possuem uma String valor armazenado para first_name da inserção da nossa seção anterior:
[ { _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex" } ]

Se você consultar um tipo que não está armazenado em first_name campo de qualquer documento, você não obterá nenhum resultado. Isso indica que é outro tipo de dados armazenado em first_name .

Você também pode consultar vários tipos de dados ao mesmo tempo com o $type operador como o seguinte:
db.mytestcoll.find( { "first_name": { $type: ["string", "null"] } } )

Porque não inserimos nenhum Null digite valores em nossa coleção, o resultado será o mesmo:
[ { _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex" } ]

Você pode usar o mesmo método com todos os tipos a seguir que discutiremos.



Números e valores numéricos


O MongoDB inclui uma variedade de tipos de dados numéricos adequados para diferentes cenários. A decisão de qual tipo usar depende da natureza dos valores que você planeja armazenar e dos casos de uso dos dados. JSON chama qualquer coisa com números de Número . Isso força o sistema a descobrir como transformá-lo no tipo de dados nativo mais próximo. Começaremos explorando os inteiros e como eles funcionam no MongoDB.

Inteiro


O Integer tipo de dados é usado para armazenar números como números inteiros sem frações ou decimais. Os inteiros podem ser valores positivos ou negativos. Existem dois tipos no MongoDB, 32-Bit Integer e 64-Bit Integer . Eles podem ser representados das duas maneiras descritas na tabela abaixo, number e alias :
  Integer type   | number |    alias     |   ------------   | -----  | ------------ |  `32-bit integer`|   16   |    "int"     | `64-bit integer`|   18   |    "long"    |

Os intervalos em que um valor pode se encaixar para cada tipo são os seguintes:
  Integer type   |    Applicable signed range     |    Applicable unsigned range    |  ------------   | ------------------------------ | ------------------------------- | `32-bit integer`| -2,147,483,648 to 2,147,483,647|  0 to 4,294,967,295             | `64-bit integer`| -9,223,372,036,854,775,808 to  |  0 to 18,446,744,073,709,551,615                         9,223,372,036,854,775,807

Os tipos acima são limitados por seu intervalo válido. Qualquer valor fora do intervalo resultará em um erro. Inserindo um Integer digite no MongoDB será parecido com o abaixo:
db.mytestcoll.insertOne({age: 26}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d14")}

E encontrar o resultado retornará o seguinte:
db.mytestcoll.find().pretty(){        _id: ObjectId("614b37296a124db40ae74d14"), age: 26}

Conforme sugerido pelos nomes, um 32-Bit Integer tem 32 bits de precisão inteira que é útil para valores inteiros menores que você não deseja armazenar como uma sequência de dígitos. Ao aumentar o tamanho do número, você pode aumentar para o 64-Bit Integer que tem 64 bits de precisão inteira e se encaixa no mesmo caso de uso que o anterior.


Duplo


No BSON, a substituição padrão do Number do JSON é o Double tipo de dados. O Double tipo de dados é usado para armazenar um valor de ponto flutuante e pode ser representado no MongoDB assim:
        Type         | Number |   Alias  |  ------------------ | ------ | -------- |       Double        |    1   | "double" |

Os números de ponto flutuante são outra maneira de expressar números decimais, mas sem precisão exata e consistente.

Os números de ponto flutuante podem funcionar com um grande número de decimais de forma eficiente, mas nem sempre exatamente. O seguinte é um exemplo de entrada de um documento com o Double digite em sua coleção:
db.mytestcoll.insertOne({testScore: 89.6}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d13")}

Pode haver pequenas diferenças entre entrada e saída ao calcular com duplicatas que podem levar a um comportamento inesperado. Ao realizar operações que exigem valores exatos, o MongoDB possui um tipo mais preciso.


Decimal128


Se você estiver trabalhando com números muito grandes com muito intervalo de ponto flutuante, então o Decimal128 O tipo de dados BSON será a melhor opção. Este será o tipo mais útil para valores que exigem muita precisão, como em casos de uso envolvendo operações monetárias exatas. O Decimal128 tipo é representado como:
        Type         | Number |   Alias   |  ------------------ | ------ | --------- |      Decimal128     |   19   | "decimal" |

O tipo BSON, Decimal128 , fornece 128 bits de representação decimal para armazenar números onde o arredondamento exato dos decimais é importante. Decimal128 suporta 34 dígitos decimais de precisão, ou um sinificand com um intervalo de -6143 a +6144. Isso permite uma grande quantidade de precisão.

Inserindo um valor usando o Decimal128 tipo de dados requer o uso de NumberDecimal() construtor com seu número como um String para evitar que o MongoDB use o tipo numérico padrão, Double .

Aqui, demonstramos isso:
db.mytestcoll.insertOne({price : NumberDecimal("5.099")}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d12")}

Ao consultar a coleção, você obtém o seguinte retorno:
db.mytestcoll.find().pretty(){        _id: ObjectId("614b37296a124db40ae74d12"),         price: "5.099" }

O valor numérico mantém sua precisão permitindo operações exatas. Para demonstrar o Decimal128 tipo versus o Double , podemos fazer o seguinte exercício.


Como a precisão pode ser perdida com base no tipo de dados


Digamos que queremos inserir um número com muitos valores decimais como um Double no MongoDB com o seguinte:
db.mytestcoll.insertOne({ price: 9999999.4999999999 }){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d24")}

Quando consultamos esses dados, obtemos o seguinte resultado:
db.mytestcoll.find().pretty(){        _id: ObjectId("614b37296a124db40ae74d24"),         price: 9999999.5}

Esse valor é arredondado para 9999999.5 , perdendo seu valor exato com o qual inserimos. Isso faz com que Double inadequado para armazenamento de números com muitos decimais.

O próximo exemplo demonstra onde a precisão será perdida ao passar um Double implicitamente com Decimal128 em vez de uma String como no exemplo anterior.

Começamos inserindo o seguinte Double novamente, mas com NumberDecimal() para torná-lo um Decimal128 tipo:
db.mytestcoll.insertOne({ price: NumberDecimal( 9999999.4999999999 ) }){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d14")}

Observação :Ao fazer essa inserção no shell do MongoDB, a seguinte mensagem de aviso é exibida:
Warning: NumberDecimal: specifying a number as argument is deprecated and may lead to loss of precision, pass a string instead

Esta mensagem de aviso indica que o número que você está tentando passar pode estar sujeito a uma perda de precisão. Eles sugerem usar uma String usando NumberDecimal() para que você não perca nenhuma precisão.

Se ignorarmos o aviso e inserirmos o documento de qualquer maneira, a perda de precisão é vista nos resultados da consulta do arredondamento do valor:
db.mytestcoll.find().pretty(){        _id: ObjectId("614b37296a124db40ae74d14"),         price: Decimal128("9999999.50000000")}

Se seguirmos o recomendado NumberDecimal() abordagem usando uma String veremos os seguintes resultados com precisão mantida:
db.mytestcoll.insertOne({ price: NumberDecimal( "9999999.4999999999" ) } )
db.mytestcoll.find().pretty(){        _id: ObjectId("614b37296a124db40ae74d14"),         price: Decimal128("9999999.4999999999")}

Para qualquer caso de uso que exija valores precisos e exatos, esse retorno pode causar problemas. Qualquer trabalho envolvendo operações monetárias é um exemplo em que a precisão será extremamente importante e ter valores exatos é fundamental para cálculos precisos. Esta demonstração destaca a importância de saber qual tipo de dados numérico será mais adequado para seus dados.



Data


O BSON Date tipo de dados é um inteiro de 64 bits que representa o número de milissegundos desde a época do Unix (1º de janeiro de 1970). Esse tipo de dados armazena a data ou hora atual e pode ser retornado como um objeto de data ou como uma string. Date é representado no MongoDB da seguinte forma:
        Type         | Number |     Alias    |  ------------------ | ------ | ------------ |        Date         |    9   |     "date"   |

Observação :BSON Date tipo é assinado. Valores negativos representam datas anteriores a 1970.

Existem três métodos para retornar valores de data.

  1. Date() - retorna uma string

  2. new Date() - retorna um objeto de data usando o ISODate() embrulho

  3. ISODate() - também retorna um objeto de data usando o ISODate() embrulho

Demonstramos essas opções abaixo:
var date1 = Date()var date2 = new Date()var date3 = ISODate()db.mytestcoll.insertOne({firstDate: date1, secondDate: date2, thirdDate: date3}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d22")}

E ao retornar:
db.mytestcoll.find().pretty(){                "_id" : ObjectId("614b37296a124db40ae74d22"),                firstDate: 'Tue Sep 28 2021 11:28:52 GMT+0200 (Central European Summer Time)',                secondDate: ISODate("2021-09-28T09:29:01.924Z"),                thirdDate: ISODate("2021-09-28T09:29:12.151Z")}


Timestamp


Há também o Timestamp tipo de dados no MongoDB para representar o tempo. No entanto, Timestamp será mais útil para uso interno e não associado à Date tipo. O tipo em si é uma sequência de caracteres usada para descrever a data e a hora em que um evento ocorre. Timestamp é um valor de 64 bits onde:
  • os 32 bits mais significativos são time_t valor (segundos desde a época do Unix)
  • os 32 bits menos significativos são um ordinal de incremento para operações em um determinado segundo

Sua representação no MongoDB terá a seguinte aparência:
        Type         | Number |     Alias    |  ------------------ | ------ | ------------ |      Timestamp      |   17   |  "timestamp" |

Ao inserir um documento que contém campos de nível superior com timestamps vazios, o MongoDB substituirá o valor do timestamp vazio pelo valor do timestamp atual. A exceção a isso é se o _id campo contém um carimbo de data/hora vazio. O valor do carimbo de data/hora sempre será inserido como está e não substituído.

Inserindo um novo Timestamp valor no MongoDB usará o new Timestamp() função e fique assim:
db.mytestcoll.insertOne( {ts: new Timestamp() });{        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d23")}

Ao consultar a coleção, você retornará um resultado semelhante a:
db.mytestcoll.find().pretty(){        "_id" : ObjectId("614b37296a124db40ae74d24"),         "ts" : Timestamp( { t: 1412180887, i: 1 })}


Objeto


O Object tipo de dados no MongoDB é usado para armazenar documentos incorporados. Um documento incorporado é uma série de documentos aninhados em key: value formato de par. Demonstramos o Object digite abaixo:
var classGrades = {"Physics": 88, "German": 92, "LitTheoery": 79}db.mytestcoll.insertOne({student_name: "John Smith", report_card: classGrades}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d18")}

Podemos então visualizar nosso novo documento:
db.mytestcoll.find().pretty(){    _id: ObjectId("614b37296a124db40ae74d18"),    student_name: 'John Smith',    report_card: {Physics: 88, German: 92, LitTheoery: 79}}

O Object tipo de dados otimiza o armazenamento de dados que são melhor acessados ​​juntos. Ele fornece algumas eficiências em relação ao armazenamento, velocidade e durabilidade, em vez de armazenar cada marca de classe, do exemplo acima, separadamente.


Dados binários


Os Binary Data , ou BinData , o tipo de dados faz exatamente o que seu nome indica e armazena dados binários para o valor de um campo. BinData é melhor usado quando você está armazenando e pesquisando dados, devido à sua eficiência na representação de matrizes de bits. Esse tipo de dado pode ser representado das seguintes maneiras:
        Type         | Number |     Alias    |  ------------------ | ------ | ------------ |      Binary data    |    5   |   "binData"  |

Aqui está um exemplo de como adicionar alguns Binary data em um documento em uma coleção:
var data = BinData(1, "111010110111100110100010101")db.mytestcoll.insertOne({binaryData: data}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d20")}

Para então ver o documento resultante:
db.mytestcoll.find().pretty(){        "_id" : ObjectId("614b37296a124db40ae74d20"),        "binaryData" : BinData(1, "111010110111100110100010101")}


ObjectId


O ObjectId type é específico do MongoDB e armazena o ID exclusivo do documento. O MongoDB fornece um _id campo para cada documento. ObjectId tem 12 bytes de tamanho e pode ser representado da seguinte forma:
        Type         | Number |     Alias    |  ------------------ | ------ | ------------ |      ObjectId       |    7   |   "objectId" |

ObjectId consiste em três partes que compõem sua composição de 12 bytes:
  • um valor de carimbo de data/hora de 4 bytes , representando a criação do ObjectId, medido em segundos desde a época do Unix
  • um valor aleatório de 5 bytes
  • um contador de incremento de 3 bytes inicializado com um valor aleatório

No MongoDB, cada documento dentro de uma coleção requer um único _id para atuar como chave primária. Se o _id for deixado vazio para um documento inserido, o MongoDB gerará automaticamente um ObjectId para o campo.

Há vários benefícios em usar ObjectIds para o _id :
  • em mongosh (shell MongoDB), o tempo de criação do ObjectId é acessível usando o ObjectId.getTimestamp() método.
  • classificação em um _id campo que armazena ObjectId tipos de dados é quase equivalente à classificação por tempo de criação.

Vimos ObjectIds em todos os exemplos até agora, e eles serão semelhantes a este:
db.mytestcoll.find().pretty(){         _id: ObjectId("614b37296a124db40ae74d19")}

Observação :os valores de ObjectId devem aumentar com o tempo, mas não são necessariamente monótonos. Isso porque eles:
  • Contêm apenas um segundo de resolução temporal, portanto, os valores criados no mesmo segundo não têm ordenação garantida
  • os valores são gerados pelos clientes, que podem ter diferentes clocks do sistema


Booleano


MongoDB tem o nativo Boolean tipo de dados para armazenar valores verdadeiros e falsos em uma coleção. Boolean no MongoDB pode ser representado da seguinte forma:
        Type         | Number |     Alias    |  ------------------ | ------ | ------------ |       Boolean       |    8   |     "bool"   |

Inserindo um documento com um Boolean tipo de dados será algo como o seguinte:
db.mytestcoll.insertOne({isCorrect: true, isIncorrect: false}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d21")}

Então, ao pesquisar o documento, o resultado aparecerá como:
db.mytestcoll.find().pretty(){    "_id" : ObjectId("614b37296a124db40ae74d21")    "isCorrect" : true,    "isIncorrect" : false}


Expressão regular


A Regular Expression tipo de dados no MongoDB permite o armazenamento de expressões regulares como o valor de um campo. MongoDB usa PCRE (Perl Compatible Regular Expression) como sua linguagem de expressão regular.

Pode ser representado da seguinte forma:
        Type         | Number |  Alias  |  ------------------ | ------ | ------- |  Regular Expression |   11   | "regex" |

O BSON permite que você evite a etapa típica de "conversão de string" que normalmente ocorre ao trabalhar com expressões regulares e bancos de dados. Esse tipo será mais útil quando você estiver escrevendo objetos de banco de dados que exigem padrões de validação ou gatilhos correspondentes.

Por exemplo, você pode inserir a Regular Expression tipo de dados assim:
db.mytestcoll.insertOne({exampleregex: /tt/}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d16")}db.mytestcoll.insertOne({exampleregext:/t+/}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d17")}

Essa sequência de declarações adicionará esses documentos à sua coleção. Você pode então consultar sua coleção para encontrar os documentos inseridos:
db.mytestcoll.find().pretty(){        _id: ObjectId("614b37296a124db40ae74d16"), exampleregex: /tt/,        _id: ObjectId("614b37296a124db40ae74d17"), exampleregex: /t+/ }

Os padrões de expressão regular são armazenados como regex e não como strings. Isso permite que você consulte uma string específica e obtenha documentos retornados que tenham uma expressão regular que corresponda à string desejada.


JavaScript (sem escopo)


Muito parecido com a Regular Expression mencionada anteriormente tipo de dados, o BSON permite que o MongoDB armazene funções JavaScript sem escopo como seu próprio tipo. O JavaScript tipo pode ser reconhecido da seguinte forma:
        Type         | Number |     Alias    |  ------------------ | ------ | ------------ |      JavaScript     |   13   | "javascript" |

Adicionando um documento à sua coleção com o JavaScript tipo de dados será algo assim:
db.mytestcoll.insertOne({jsCode: "function(){var x; x=1}"}){        "acknowledged": true,        "insertedId": ObjectId("614b37296a124db40ae74d122")}

Essa funcionalidade permite que você armazene funções JavaScript dentro de suas coleções do MongoDB, se necessário para um caso de uso específico.

Observação :Com o MongoDB versão 4.4 e superior, um tipo alternativo de JavaScript, o JavaScript with Scope tipo de dados, foi preterido


Conclusão


Neste artigo, abordamos a maioria dos tipos de dados comuns que são úteis ao trabalhar com bancos de dados MongoDB. Existem tipos adicionais que não são explicitamente abordados neste guia que podem ser úteis dependendo do caso de uso. Começar conhecendo esses tipos abrange a maioria dos casos de uso. É uma base sólida para começar a modelar seu banco de dados MongoDB.

É importante saber quais tipos de dados estão disponíveis para você ao usar um banco de dados para que você esteja usando valores válidos e operando nos dados com os resultados esperados. Existem riscos que você pode correr sem digitar seus dados corretamente, como demonstrado no Double versus Decimal128 exercício. É importante pensar sobre isso antes de se comprometer com qualquer tipo.

Se você estiver interessado em verificar o Prisma com um banco de dados MongoDB, consulte a documentação do conector de dados.