Introduzione
Quando usi MongoDB, hai la possibilità di essere flessibile con la struttura dei tuoi dati. Non sei vincolato al mantenimento di un determinato schema in cui tutti i tuoi documenti devono rientrare. Per ogni dato campo in un documento, puoi utilizzare uno qualsiasi dei tipi di dati disponibili supportato da MongoDB. Nonostante questo modo di lavorare predefinito, puoi imporre uno schema JSON in MongoDB per aggiungere la convalida alle tue raccolte, se lo desideri. Non entreremo nei dettagli della progettazione dello schema in questa guida, ma può avere un effetto sulla tipizzazione dei dati se implementata.
I tipi di dati specificano un modello generale per i dati che accettano e archiviano. È fondamentale capire quando scegliere un determinato tipo di dati rispetto a un altro quando si pianifica il database. Il tipo scelto determinerà come puoi operare sui tuoi dati e come vengono archiviati.
JSON e BSON
Prima di entrare nei dettagli di tipi di dati specifici, è importante comprendere come MongoDB archivia i dati. MongoDB e molti altri database NoSQL basati su documenti utilizzano JSON (JavaScript Object Notation) per rappresentare i record di dati come documenti.
Ci sono molti vantaggi nell'usare JSON per archiviare i dati. Alcuni di loro sono:
- facilità di lettura, apprendimento e familiarità tra gli sviluppatori
- flessibilità nel formato, sparso, gerarchico o profondamente nidificato
- Autodescrittivo, che consente alle applicazioni di operare facilmente con i dati JSON
- consente di concentrarsi su un numero minimo di tipi di base
JSON supporta tutti i tipi di dati di base come stringa, numero, booleano, ecc. MongoDB archivia effettivamente i record di dati come documenti JSON (BSON) con codifica binaria. Come JSON, BSON supporta l'incorporamento di documenti e array all'interno di altri documenti e array. BSON consente tipi di dati aggiuntivi che non sono disponibili per JSON.
Quali sono i tipi di dati in MongoDB?
Prima di entrare nei dettagli, diamo una visione generale di quali tipi di dati sono supportati in MongoDB.
MongoDB supporta una gamma di tipi di dati adatti a vari tipi di dati sia semplici che complessi. Questi includono:
Testo
String
Numerico
32-Bit Integer
64-Bit Integer
Double
Decimal128
Data/Ora
Date
Timestamp
Altro
Object
Array
Binary Data
ObjectId
Boolean
Null
Regular Expression
JavaScript
Min Key
Max Key
In MongoDB, ogni tipo BSON ha identificatori sia intero che stringa. Tratteremo i più comuni di questi in modo più approfondito in questa guida.
Tipi di stringhe
Il tipo di stringa è il tipo di dati MongoDB più comunemente utilizzato. Qualsiasi valore scritto tra virgolette ""
in JSON è un valore stringa. Qualsiasi valore che desideri venga archiviato come testo sarà meglio digitato come String
. Le stringhe BSON sono UTF-8 e sono rappresentate in MongoDB come:
Type | Number | Alias | ------------------ | ------ | -------- | String | 2 | "string" |
In genere, i driver per i linguaggi di programmazione vengono convertiti dal formato stringa del linguaggio a UTF-8 durante la serializzazione e la deserializzazione di BSON. Questo rende BSON un metodo interessante per memorizzare facilmente i caratteri internazionali, ad esempio.
Inserimento di un documento con una String
il tipo di dati sarà simile a questo:
db.mytestcoll.insertOne({first_name: "Alex"}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d15")}
Interrogare la raccolta restituirà quanto segue:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex"}
Utilizzo del $type
operatore
Prima di passare al nostro prossimo tipo di dati, è importante sapere come digitare controlla il valore prima di effettuare qualsiasi inserimento. Useremo l'esempio precedente per dimostrare l'uso del $type
operatore in MongoDB.
Diciamo che è passato un po' di tempo da quando abbiamo lavorato con mytestcoll
raccolta di prima. Vogliamo inserire alcuni documenti aggiuntivi nella raccolta con il first_name
campo. Per verificare che abbiamo usato String
come tipo di dati archiviato come valore di first_name
originariamente, possiamo eseguire quanto segue utilizzando l'alias o il valore numerico del tipo di dati:
db.mytestcoll.find( { "first_name": { $type: "string" } } )
Oppure
db.mytestcoll.find( { "first_name": { $type: 2 } } )
Entrambe le query restituiscono un output di tutti i documenti che hanno una String
valore memorizzato per first_name
dall'inserimento della nostra sezione precedente:
[ { _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex" } ]
Se richiedi un tipo che non è memorizzato nel first_name
campo di qualsiasi documento, non otterrai alcun risultato. Ciò indica che si tratta di un altro tipo di dati archiviato in first_name
.
Puoi anche eseguire query per più tipi di dati alla volta con il $type
operatore come il seguente:
db.mytestcoll.find( { "first_name": { $type: ["string", "null"] } } )
Perché non abbiamo inserito alcun Null
digita i valori nella nostra raccolta, il risultato sarà lo stesso:
[ { _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex" } ]
Puoi utilizzare lo stesso metodo con tutti i seguenti tipi di cui parleremo.
Numeri e valori numerici
MongoDB include una gamma di tipi di dati numerici adatti a diversi scenari. La decisione del tipo da utilizzare dipende dalla natura dei valori che prevedi di archiviare e dai casi d'uso per i dati. JSON chiama qualsiasi cosa con numeri un Numero . Ciò costringe il sistema a capire come trasformarlo nel tipo di dati nativo più vicino. Inizieremo esplorando gli interi e come funzionano in MongoDB.
Intero
Il Integer
il tipo di dati viene utilizzato per memorizzare i numeri come numeri interi senza frazioni o decimali. Gli interi possono essere valori positivi o negativi. Esistono due tipi in MongoDB, 32-Bit Integer
e 64-Bit Integer
. Possono essere rappresentati nei due modi illustrati nella tabella seguente, number
e alias
:
Integer type | number | alias | ------------ | ----- | ------------ | `32-bit integer`| 16 | "int" | `64-bit integer`| 18 | "long" |
Gli intervalli in cui un valore può rientrare per ogni tipo sono i seguenti:
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
I tipi sopra sono limitati dal loro intervallo valido. Qualsiasi valore al di fuori dell'intervallo genererà un errore. Inserimento di un Integer
digita in MongoDB sarà simile al seguente:
db.mytestcoll.insertOne({age: 26}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d14")}
E trovare il risultato restituirà quanto segue:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d14"), age: 26}
Come suggerito dai nomi, un 32-Bit Integer
ha 32 bit di precisione intera, utile per valori interi più piccoli che non si desidera memorizzare come sequenza di cifre. Aumentando la dimensione del numero, puoi aumentare fino al 64-Bit Integer
che ha 64 bit di precisione intera e si adatta allo stesso caso d'uso del primo.
Doppio
In BSON, la sostituzione predefinita per il Numero di JSON è il Double
tipo di dati. Il Double
il tipo di dati viene utilizzato per memorizzare un valore a virgola mobile e può essere rappresentato in MongoDB in questo modo:
Type | Number | Alias | ------------------ | ------ | -------- | Double | 1 | "double" |
I numeri in virgola mobile sono un altro modo per esprimere i numeri decimali, ma senza una precisione esatta e coerente.
I numeri in virgola mobile possono funzionare con un numero elevato di decimali in modo efficiente ma non sempre esattamente. Quello che segue è un esempio di inserimento di un documento con il Double
digita nella tua raccolta:
db.mytestcoll.insertOne({testScore: 89.6}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d13")}
Possono esserci lievi differenze tra input e output durante il calcolo con doppi che potrebbero potenzialmente portare a comportamenti imprevisti. Quando si eseguono operazioni che richiedono valori esatti, MongoDB ha un tipo più preciso.
Decimal128
Se stai lavorando con numeri molto grandi con molti intervalli in virgola mobile, allora Decimal128
Il tipo di dati BSON sarà l'opzione migliore. Questo sarà il tipo più utile per i valori che richiedono molta precisione, come nei casi d'uso che coinvolgono operazioni monetarie esatte. Il Decimal128
il tipo è rappresentato come:
Type | Number | Alias | ------------------ | ------ | --------- | Decimal128 | 19 | "decimal" |
Il tipo BSON, Decimal128
, fornisce 128 bit di rappresentazione decimale per la memorizzazione di numeri in cui è importante arrotondare esattamente i decimali. Decimal128
supporta 34 cifre decimali di precisione o un sinificando con un intervallo da -6143 a +6144. Ciò consente un'elevata precisione.
Inserimento di un valore utilizzando il Decimal128
il tipo di dati richiede l'utilizzo di NumberDecimal()
costruttore con il tuo numero come String
per impedire a MongoDB di utilizzare il tipo numerico predefinito, Double
.
Qui, lo dimostriamo:
db.mytestcoll.insertOne({price : NumberDecimal("5.099")}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d12")}
Quando si interroga la raccolta, si ottiene il seguente ritorno:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d12"), price: "5.099" }
Il valore numerico mantiene la sua precisione consentendo operazioni esatte. Per dimostrare il Decimal128
digitare contro il Double
, possiamo eseguire il seguente esercizio.
Come si può perdere la precisione in base al tipo di dati
Supponiamo di voler inserire un numero con molti valori decimali come Double
in MongoDB con quanto segue:
db.mytestcoll.insertOne({ price: 9999999.4999999999 }){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d24")}
Quando eseguiamo una query per questi dati, otteniamo il seguente risultato:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d24"), price: 9999999.5}
Questo valore arrotonda per eccesso a 9999999.5
, perdendo il valore esatto con cui l'abbiamo inserito. Questo rende Double
inadatto per la memorizzazione di numeri con molti decimali.
Il prossimo esempio mostra dove la precisione andrà persa quando si passa un Double
implicitamente con Decimal128
invece di una String
come nell'esempio precedente.
Iniziamo inserendo il seguente Double
di nuovo ma con NumberDecimal()
per renderlo un Decimal128
digita:
db.mytestcoll.insertOne({ price: NumberDecimal( 9999999.4999999999 ) }){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d14")}
Nota :Quando si effettua questo inserimento nella shell di MongoDB, viene visualizzato il seguente messaggio di avviso:
Warning: NumberDecimal: specifying a number as argument is deprecated and may lead to loss of precision, pass a string instead
Questo messaggio di avviso indica che il numero che stai tentando di passare potrebbe subire una perdita di precisione. Suggeriscono di usare una String
usando NumberDecimal()
in modo da non perdere alcuna precisione.
Se ignoriamo l'avviso e inseriamo comunque il documento, la perdita di precisione si vede nei risultati della query dall'arrotondamento per eccesso del valore:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d14"), price: Decimal128("9999999.50000000")}
Se seguiamo il NumberDecimal()
consigliato avvicinarsi usando una String
vedremo i seguenti risultati con precisione mantenuta:
db.mytestcoll.insertOne({ price: NumberDecimal( "9999999.4999999999" ) } )
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d14"), price: Decimal128("9999999.4999999999")}
Per qualsiasi caso d'uso che richieda valori precisi ed esatti, questo ritorno potrebbe causare problemi. Qualsiasi lavoro che coinvolga operazioni monetarie è un esempio in cui la precisione sarà estremamente importante e avere valori esatti è fondamentale per calcoli accurati. Questa dimostrazione mette in evidenza l'importanza di sapere quale tipo di dati numerico sarà più adatto per i tuoi dati.
Data
Il BSON Date
il tipo di dati è un numero intero a 64 bit che rappresenta il numero di millisecondi dall'epoca di Unix (1 gennaio 1970). Questo tipo di dati memorizza la data o l'ora corrente e può essere restituito come oggetto data o come stringa. Date
è rappresentato in MongoDB come segue:
Type | Number | Alias | ------------------ | ------ | ------------ | Date | 9 | "date" |
Nota :BSON Date
il tipo è firmato. I valori negativi rappresentano date precedenti al 1970.
Esistono tre metodi per restituire i valori di data.
-
Date()
- restituisce una stringa -
new Date()
- restituisce un oggetto data utilizzandoISODate()
involucro -
ISODate()
- restituisce anche un oggetto data utilizzandoISODate()
involucro
Dimostriamo queste opzioni di seguito:
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 al ritorno:
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
C'è anche il Timestamp
tipo di dati in MongoDB per rappresentare l'ora. Tuttavia, Timestamp
sarà molto utile per uso interno e non lo è associato alla Date
genere. Il tipo stesso è una sequenza di caratteri utilizzata per descrivere la data e l'ora in cui si verifica un evento. Timestamp
è un valore a 64 bit dove:
- i 32 bit più significativi sono
time_t
valore (secondi dall'epoca di Unix) - i 32 bit meno significativi sono un
ordinal
incrementale per operazioni entro un dato secondo
La sua rappresentazione in MongoDB avrà il seguente aspetto:
Type | Number | Alias | ------------------ | ------ | ------------ | Timestamp | 17 | "timestamp" |
Quando si inserisce un documento che contiene campi di primo livello con timestamp vuoti, MongoDB sostituirà il valore di timestamp vuoto con il valore di timestamp corrente. L'eccezione a questo è se il _id
il campo contiene un timestamp vuoto. Il valore del timestamp verrà sempre inserito così com'è e non sostituito.
Inserimento di un nuovo Timestamp
valore in MongoDB utilizzerà il new Timestamp()
funzione e assomiglia a questo:
db.mytestcoll.insertOne( {ts: new Timestamp() });{ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d23")}
Quando esegui una query sulla raccolta, restituirai un risultato simile a:
db.mytestcoll.find().pretty(){ "_id" : ObjectId("614b37296a124db40ae74d24"), "ts" : Timestamp( { t: 1412180887, i: 1 })}
Oggetto
L'Object
il tipo di dati in MongoDB viene utilizzato per archiviare i documenti incorporati. Un documento incorporato è una serie di documenti nidificati in key: value
formato coppia. Dimostriamo l'Object
digita sotto:
var classGrades = {"Physics": 88, "German": 92, "LitTheoery": 79}db.mytestcoll.insertOne({student_name: "John Smith", report_card: classGrades}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d18")}
Possiamo quindi visualizzare il nostro nuovo documento:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d18"), student_name: 'John Smith', report_card: {Physics: 88, German: 92, LitTheoery: 79}}
L'Object
il tipo di dati ottimizza per la memorizzazione dei dati a cui è possibile accedere al meglio insieme. Fornisce alcune efficienze in termini di archiviazione, velocità e durata invece di memorizzare separatamente ogni segno di classe, dall'esempio sopra.
Dati binari
I Binary data
o BinData
, il tipo di dati fa esattamente ciò che implica il suo nome e memorizza i dati binari per il valore di un campo. BinData
viene utilizzato al meglio durante l'archiviazione e la ricerca di dati, grazie alla sua efficienza nella rappresentazione di array di bit. Questo tipo di dati può essere rappresentato nei seguenti modi:
Type | Number | Alias | ------------------ | ------ | ------------ | Binary data | 5 | "binData" |
Ecco un esempio di aggiunta di alcuni Binary data
in un documento in una raccolta:
var data = BinData(1, "111010110111100110100010101")db.mytestcoll.insertOne({binaryData: data}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d20")}
Per poi vedere il documento risultante:
db.mytestcoll.find().pretty(){ "_id" : ObjectId("614b37296a124db40ae74d20"), "binaryData" : BinData(1, "111010110111100110100010101")}
ObjectId
Il ObjectId
type è specifico di MongoDB e memorizza l'ID univoco del documento. MongoDB fornisce un _id
campo per ogni documento. ObjectId ha una dimensione di 12 byte e può essere rappresentato come segue:
Type | Number | Alias | ------------------ | ------ | ------------ | ObjectId | 7 | "objectId" |
ObjectId è costituito da tre parti che compongono la sua struttura a 12 byte:
- un valore timestamp a 4 byte , che rappresenta la creazione dell'ObjectId, misurata in secondi dall'epoca di Unix
- un valore casuale a 5 byte
- un contatore incrementale a 3 byte inizializzato su un valore casuale
In MongoDB, ogni documento all'interno di una raccolta richiede un _id
univoco agire come chiave primaria. Se il _id
campo viene lasciato vuoto per un documento inserito, MongoDB genererà automaticamente un ObjectId per il campo.
Ci sono diversi vantaggi nell'usare ObjectIds per _id
:
- in
mongosh
(shell MongoDB), l'ora di creazione diObjectId
è accessibile utilizzandoObjectId.getTimestamp()
metodo. - ordinamento su un
_id
campo che memorizzaObjectId
tipi di dati è un equivalente vicino all'ordinamento per ora di creazione.
Finora abbiamo visto ObjectIds in tutti gli esempi e saranno simili a questo:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d19")}
Nota :i valori ObjectId dovrebbero aumentare nel tempo, tuttavia non sono necessariamente monotoni. Questo perché loro:
- Contengono solo un secondo di risoluzione temporale, quindi i valori creati nello stesso secondo non hanno un ordinamento garantito
- I valori sono generati dai client, che possono avere clock di sistema diversi
Booleano
MongoDB ha il Boolean
nativo tipo di dati per la memorizzazione di valori true e false all'interno di una raccolta. Boolean
in MongoDB può essere rappresentato come segue:
Type | Number | Alias | ------------------ | ------ | ------------ | Boolean | 8 | "bool" |
Inserimento di un documento con un Boolean
il tipo di dati sarà simile al seguente:
db.mytestcoll.insertOne({isCorrect: true, isIncorrect: false}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d21")}
Quindi durante la ricerca del documento il risultato apparirà come:
db.mytestcoll.find().pretty(){ "_id" : ObjectId("614b37296a124db40ae74d21") "isCorrect" : true, "isIncorrect" : false}
Espressione regolare
L'Regular Expression
il tipo di dati in MongoDB consente la memorizzazione di espressioni regolari come valore di un campo. MongoDB usa PCRE (Perl Compatible Regular Expression) come linguaggio di espressioni regolari.
Può essere rappresentato nel modo seguente:
Type | Number | Alias | ------------------ | ------ | ------- | Regular Expression | 11 | "regex" |
BSON consente di evitare il tipico passaggio di "conversione da stringa" che si verifica comunemente quando si lavora con espressioni regolari e database. Questo tipo sarà molto utile quando si scrivono oggetti di database che richiedono modelli di convalida o trigger di corrispondenza.
Ad esempio, puoi inserire l'Regular Expression
tipo di dati come questo:
db.mytestcoll.insertOne({exampleregex: /tt/}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d16")}db.mytestcoll.insertOne({exampleregext:/t+/}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d17")}
Questa sequenza di dichiarazioni aggiungerà questi documenti alla tua collezione. Puoi quindi interrogare la tua collezione per trovare i documenti inseriti:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d16"), exampleregex: /tt/, _id: ObjectId("614b37296a124db40ae74d17"), exampleregex: /t+/ }
I modelli di espressione regolare vengono archiviati come regex e non come stringhe. Ciò ti consente di eseguire query per una determinata stringa e ottenere documenti restituiti con un'espressione regolare corrispondente alla stringa desiderata.
JavaScript (senza ambito)
Proprio come la menzionata Regular Expression
tipo di dati, BSON consente a MongoDB di archiviare funzioni JavaScript senza ambito come proprio tipo. Il JavaScript
tipo può essere riconosciuto come segue:
Type | Number | Alias | ------------------ | ------ | ------------ | JavaScript | 13 | "javascript" |
Aggiunta di un documento alla tua raccolta con JavaScript
il tipo di dati sarà simile a questo:
db.mytestcoll.insertOne({jsCode: "function(){var x; x=1}"}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d122")}
Questa funzionalità ti consente di memorizzare le funzioni JavaScript all'interno delle tue raccolte MongoDB, se necessario per un caso d'uso particolare.
Nota :Con MongoDB versione 4.4 e successive, un tipo JavaScript alternativo, il JavaScript with Scope
tipo di dati, è stato deprecato
Conclusione
In questo articolo, abbiamo trattato la maggior parte dei tipi di dati comuni che sono utili quando si lavora con i database MongoDB. Esistono tipi aggiuntivi che non sono trattati in modo esplicito in questa guida che potrebbero essere utili a seconda del caso d'uso. Iniziare conoscendo questi tipi copre la maggior parte dei casi d'uso. È una solida base per iniziare a modellare il tuo database MongoDB.
È importante sapere quali tipi di dati sono disponibili quando si utilizza un database in modo da utilizzare valori validi e operare sui dati con risultati previsti. Ci sono dei rischi in cui potresti incorrere senza digitare correttamente i tuoi dati, come mostrato nel Double
rispetto a Decimal128
esercizio. È importante pensarci prima di impegnarsi in un determinato tipo.
Se sei interessato a controllare Prisma con un database MongoDB, puoi consultare la documentazione del connettore dati.