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.
-
Date()
- retorna uma string
-
new Date()
- retorna um objeto de data usando oISODate()
embrulho
-
ISODate()
- também retorna um objeto de data usando oISODate()
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 doObjectId
é acessível usando oObjectId.getTimestamp()
método. - classificação em um
_id
campo que armazenaObjectId
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.