Introduktion
När du använder MongoDB har du möjlighet att vara flexibel med strukturen på dina data. Du är inte låst till att upprätthålla ett visst schema som alla dina dokument måste passa in i. För varje givet fält i ett dokument kan du använda vilken som helst av de tillgängliga datatyperna stöds av MongoDB. Trots detta standardsätt att arbeta kan du införa ett JSON-schema i MongoDB för att lägga till validering på dina samlingar om så önskas. Vi går inte in på detaljerna om schemadesign i den här guiden, men det kan ha en effekt på datainmatning om det implementeras.
Datatyper anger ett allmänt mönster för den data de accepterar och lagrar. Det är ytterst viktigt att förstå när man ska välja en viss datatyp framför en annan när man planerar sin databas. Den valda typen kommer att diktera hur du kan hantera din data och hur den lagras.
JSON och BSON
Innan du går in på detaljerna för specifika datatyper är det viktigt att ha en förståelse för hur MongoDB lagrar data. MongoDB och många andra dokumentbaserade NoSQL-databaser använder JSON (JavaScript Object Notation) för att representera dataposter som dokument.
Det finns många fördelar med att använda JSON för att lagra data. Några av dem är:
- lätthet att läsa, lära sig och dess förtrogenhet bland utvecklare
- flexibilitet i format, oavsett om det är gles, hierarkiskt eller djupt kapslat
- självbeskrivande, vilket gör att applikationer enkelt kan arbeta med JSON-data
- gör det möjligt att fokusera på ett minimalt antal grundläggande typer
JSON stöder alla grundläggande datatyper som sträng, nummer, boolean, etc. MongoDB lagrar faktiskt dataposter som binärkodade JSON-dokument (BSON). Precis som JSON stöder BSON inbäddning av dokument och arrayer i andra dokument och arrayer. BSON tillåter ytterligare datatyper som inte är tillgängliga för JSON.
Vilka är datatyperna i MongoDB?
Innan vi går in i detalj, låt oss ta en bred bild av vilka datatyper som stöds i MongoDB.
MongoDB stöder en rad datatyper som lämpar sig för olika typer av både enkla och komplexa data. Dessa inkluderar:
Sms:a
String
Numerisk
32-Bit Integer
64-Bit Integer
Double
Decimal128
Datum/tid
Date
Timestamp
Annat
Object
Array
Binary Data
ObjectId
Boolean
Null
Regular Expression
JavaScript
Min Key
Max Key
I MongoDB har varje BSON-typ både ett heltal och strängidentifierare. Vi kommer att täcka de vanligaste av dessa mer ingående i den här guiden.
Strängtyper
Strängtypen är den mest använda MongoDB-datatypen. Alla värden skrivna inuti dubbla citattecken ""
i JSON är ett strängvärde. Alla värden som du vill ska lagras som text skrivs bäst som en String
. BSON-strängar är UTF-8 och representeras i MongoDB som:
Type | Number | Alias | ------------------ | ------ | -------- | String | 2 | "string" |
Generellt kommer drivrutiner för programmeringsspråk att konvertera från språkets strängformat till UTF-8 vid serialisering och avserialisering av BSON. Detta gör BSON till en attraktiv metod för att till exempel enkelt lagra internationella tecken.
Infoga ett dokument med en String
datatypen kommer att se ut ungefär så här:
db.mytestcoll.insertOne({first_name: "Alex"}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d15")}
Om du frågar efter samlingen returneras följande:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex"}
Använda $type
operatör
Innan du går vidare till vår nästa datatyp är det viktigt att veta hur du kan skriva kontrollera värdet innan du gör några infogar. Vi kommer att använda föregående exempel för att demonstrera hur vi använder $type
operatör i MongoDB.
Låt oss säga att det har gått ett tag sedan vi arbetade med mytestcoll
samling från tidigare. Vi vill infoga några ytterligare dokument i samlingen med first_name
fält. För att kontrollera att vi använde String
som datatypen lagrad som ett värde på first_name
ursprungligen kan vi köra följande med antingen alias- eller nummervärdet för datatypen:
db.mytestcoll.find( { "first_name": { $type: "string" } } )
Eller
db.mytestcoll.find( { "first_name": { $type: 2 } } )
Båda frågorna returnerar en utdata av alla dokument som har en String
värde lagrat för first_name
från vårt tidigare avsnitts infogning:
[ { _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex" } ]
Om du frågar efter en typ som inte är lagrad i first_name
fältet i något dokument får du inget resultat. Detta indikerar att det är en annan datatyp som lagras i first_name
.
Du kan också fråga efter flera datatyper samtidigt med $type
operatör som följande:
db.mytestcoll.find( { "first_name": { $type: ["string", "null"] } } )
Eftersom vi inte infogade någon Null
skriv in värden i vår samling, resultatet blir detsamma:
[ { _id: ObjectId("614b37296a124db40ae74d15"), first_name: "Alex" } ]
Du kan använda samma metod med alla följande typer som vi kommer att diskutera.
Siffror och numeriska värden
MongoDB innehåller en rad numeriska datatyper som är lämpliga för olika scenarier. Att bestämma vilken typ som ska användas beror på arten av de värden du planerar att lagra och dina användningsfall för data. JSON kallar allt med nummer ett Nummer . Det tvingar systemet att ta reda på hur det ska omvandlas till närmaste inbyggda datatyp. Vi börjar med att utforska heltal och hur de fungerar i MongoDB.
Heltal
Integer
datatyp används för att lagra tal som heltal utan bråktal eller decimaler. Heltal kan antingen vara positiva eller negativa värden. Det finns två typer i MongoDB, 32-Bit Integer
och 64-Bit Integer
. De kan representeras på de två sätt som visas i tabellen nedan, number
och alias
:
Integer type | number | alias | ------------ | ----- | ------------ | `32-bit integer`| 16 | "int" | `64-bit integer`| 18 | "long" |
De intervall som ett värde kan passa in i för varje typ är följande:
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
Typerna ovan är begränsade av deras giltiga intervall. Alla värden utanför intervallet kommer att resultera i ett fel. Infoga ett Integer
skriv in MongoDB kommer att se ut som nedan:
db.mytestcoll.insertOne({age: 26}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d14")}
Och att hitta resultatet kommer att returnera följande:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d14"), age: 26}
Som föreslagits av namnen, ett 32-Bit Integer
har 32 bitars heltalsprecision vilket är användbart för mindre heltalsvärden som du inte vill lagra som en sekvens av siffror. När du växer i antalsstorlek kan du komma upp till 64-Bit Integer
som har 64 bitars heltalsprecision och passar samma användningsfall som den förra.
Dubbel
I BSON är standardersättningen för JSONs nummer är Double
data typ. Double
datatyp används för att lagra ett flyttalsvärde och kan representeras i MongoDB så här:
Type | Number | Alias | ------------------ | ------ | -------- | Double | 1 | "double" |
Flyttal är ett annat sätt att uttrycka decimaltal, men utan exakt, konsekvent precision.
Flyttal kan fungera med ett stort antal decimaler effektivt men inte alltid exakt. Följande är ett exempel på hur du skriver in ett dokument med Double
skriv i din samling:
db.mytestcoll.insertOne({testScore: 89.6}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d13")}
Det kan finnas små skillnader mellan input och output vid beräkning med dubblar som potentiellt kan leda till oväntat beteende. När man utför operationer som kräver exakta värden har MongoDB en mer exakt typ.
Decimal128
Om du arbetar med mycket stora siffror med många flyttalsintervall, är Decimal128
BSON-datatyp kommer att vara det bästa alternativet. Detta kommer att vara den mest användbara typen för värden som kräver mycket precision som i användningsfall som involverar exakta monetära operationer. Decimal128
typ representeras som:
Type | Number | Alias | ------------------ | ------ | --------- | Decimal128 | 19 | "decimal" |
BSON-typen, Decimal128
, ger 128 bitars decimalrepresentation för lagring av tal där det är viktigt att avrunda decimaler exakt. Decimal128
stöder 34 decimalsiffror med precision, eller en sinificand med ett intervall på -6143 till +6144. Detta möjliggör en hög precision.
Infoga ett värde med Decimal128
datatypen kräver att NumberDecimal()
används konstruktor med ditt nummer som en String
för att hindra MongoDB från att använda standardnumerisk typ, Double
.
Här visar vi detta:
db.mytestcoll.insertOne({price : NumberDecimal("5.099")}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d12")}
När du frågar efter samlingen får du följande retur:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d12"), price: "5.099" }
Det numeriska värdet bibehåller sin precision vilket möjliggör exakta operationer. För att demonstrera Decimal128
typ kontra Double
, vi kan gå igenom följande övning.
Hur precision kan förloras baserat på datatyp
Säg att vi vill infoga ett tal med många decimaler som en Double
till MongoDB med följande:
db.mytestcoll.insertOne({ price: 9999999.4999999999 }){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d24")}
När vi frågar efter denna data får vi följande resultat:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d24"), price: 9999999.5}
Detta värde avrundas uppåt till 9999999.5
, förlorar sitt exakta värde som vi matade in det med. Detta gör Double
dåligt lämpad för lagring av tal med många decimaler.
Nästa exempel visar var precision går förlorad när du skickar en Double
implicit med Decimal128
istället för en String
som i föregående exempel.
Vi börjar med att infoga följande Double
igen men med NumberDecimal()
för att göra det till en Decimal128
typ:
db.mytestcoll.insertOne({ price: NumberDecimal( 9999999.4999999999 ) }){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d14")}
Obs :När du gör denna infogning i MongoDB-skalet, visas följande varningsmeddelande:
Warning: NumberDecimal: specifying a number as argument is deprecated and may lead to loss of precision, pass a string instead
Detta varningsmeddelande indikerar att numret du försöker passera kan vara föremål för en förlust av precision. De föreslår att du använder en String
med NumberDecimal()
så att du inte tappar precisionen.
Om vi ignorerar varningen och sätter in dokumentet ändå, ses förlusten av precision i sökresultatet från avrundningen uppåt av värdet:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d14"), price: Decimal128("9999999.50000000")}
Om vi följer den rekommenderade NumberDecimal()
tillvägagångssätt med en String
vi kommer att se följande resultat med bibehållen precision:
db.mytestcoll.insertOne({ price: NumberDecimal( "9999999.4999999999" ) } )
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d14"), price: Decimal128("9999999.4999999999")}
För alla användningsfall som kräver exakta, exakta värden kan denna retur orsaka problem. Allt arbete som involverar monetära operationer är ett exempel där precision kommer att vara extremt viktigt och att ha exakta värden är avgörande för korrekta beräkningar. Den här demonstrationen understryker vikten av att veta vilken numerisk datatyp som passar bäst för din data.
Datum
BSON Date
datatypen är ett 64-bitars heltal som representerar antalet millisekunder sedan Unix-epoken (1 januari 1970). Denna datatyp lagrar aktuellt datum eller tid och kan returneras som antingen ett datumobjekt eller som en sträng. Date
representeras i MongoDB enligt följande:
Type | Number | Alias | ------------------ | ------ | ------------ | Date | 9 | "date" |
Obs :BSON Date
typ är signerad. Negativa värden representerar datum före 1970.
Det finns tre metoder för att returnera datumvärden.
-
Date()
- returnerar en sträng -
new Date()
- returnerar ett datumobjekt medISODate()
omslag -
ISODate()
- returnerar också ett datumobjekt medISODate()
omslag
Vi visar dessa alternativ nedan:
var date1 = Date()var date2 = new Date()var date3 = ISODate()db.mytestcoll.insertOne({firstDate: date1, secondDate: date2, thirdDate: date3}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d22")}
Och vid retur:
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")}
Tidsstämpel
Det finns också Timestamp
datatyp i MongoDB för att representera tid. Men Timestamp
kommer att vara mest användbar för internt bruk och är det inte kopplat till Date
typ. Själva typen är en sekvens av tecken som används för att beskriva datum och tid när en händelse inträffar. Timestamp
är ett 64-bitars värde där:
- de viktigaste 32 bitarna är
time_t
värde (sekunder sedan Unix-epoken) - de minst signifikanta 32 bitarna är en inkrementerande
ordinal
för operationer inom en given sekund
Dess representation i MongoDB kommer att se ut som följer:
Type | Number | Alias | ------------------ | ------ | ------------ | Timestamp | 17 | "timestamp" |
När du infogar ett dokument som innehåller fält på toppnivå med tomma tidsstämplar, kommer MongoDB att ersätta det tomma tidsstämpelvärdet med det aktuella tidsstämpelvärdet. Undantaget från detta är om _id
fältet innehåller en tom tidsstämpel. Tidsstämpelvärdet kommer alltid att infogas som det är och inte ersättas.
Infogar en ny Timestamp
värde i MongoDB kommer att använda new Timestamp()
funktion och ser ut ungefär så här:
db.mytestcoll.insertOne( {ts: new Timestamp() });{ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d23")}
När du frågar efter samlingen returnerar du ett resultat som liknar:
db.mytestcoll.find().pretty(){ "_id" : ObjectId("614b37296a124db40ae74d24"), "ts" : Timestamp( { t: 1412180887, i: 1 })}
Objekt
Object
datatyp i MongoDB används för att lagra inbäddade dokument. Ett inbäddat dokument är en serie kapslade dokument i key: value
parformat. Vi demonstrerar Object
skriv nedan:
var classGrades = {"Physics": 88, "German": 92, "LitTheoery": 79}db.mytestcoll.insertOne({student_name: "John Smith", report_card: classGrades}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d18")}
Vi kan sedan se vårt nya dokument:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d18"), student_name: 'John Smith', report_card: {Physics: 88, German: 92, LitTheoery: 79}}
Object
datatyp optimerar för lagring av data som är bäst åtkomlig tillsammans. Det ger vissa effektiviteter kring lagring, hastighet och hållbarhet i motsats till att lagra varje klassmärke, från exemplet ovan, separat.
Binära data
Binary Data
, eller BinData
, datatyp gör exakt vad dess namn antyder och lagrar binär data för ett fälts värde. BinData
används bäst när du lagrar och söker efter data, på grund av dess effektivitet när det gäller att representera bitmatriser. Denna datatyp kan representeras på följande sätt:
Type | Number | Alias | ------------------ | ------ | ------------ | Binary data | 5 | "binData" |
Här är ett exempel på att lägga till några Binary data
till ett dokument i en samling:
var data = BinData(1, "111010110111100110100010101")db.mytestcoll.insertOne({binaryData: data}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d20")}
För att sedan se det resulterande dokumentet:
db.mytestcoll.find().pretty(){ "_id" : ObjectId("614b37296a124db40ae74d20"), "binaryData" : BinData(1, "111010110111100110100010101")}
ObjectId
ObjectId
typen är specifik för MongoDB och den lagrar dokumentets unika ID. MongoDB tillhandahåller ett _id
fält för varje dokument. ObjectId är 12 byte stor och kan representeras enligt följande:
Type | Number | Alias | ------------------ | ------ | ------------ | ObjectId | 7 | "objectId" |
ObjectId består av tre delar som utgör dess 12-byte makeup:
- ett 4-byte tidsstämpelvärde , som representerar objekt-ID:s skapelse, mätt i sekunder sedan Unix-epoken
- ett 5-byte slumpmässigt värde
- en 3-byte inkrementerande räknare initieras till ett slumpmässigt värde
I MongoDB kräver varje dokument i en samling ett unikt _id
att fungera som en primärnyckel. Om _id
fältet lämnas tomt för ett infogat dokument, kommer MongoDB automatiskt att generera ett ObjectId för fältet.
Det finns flera fördelar med att använda ObjectIds för _id
:
- på
mongosh
(MongoDB-skal), skapandet avObjectId
är tillgänglig medObjectId.getTimestamp()
metod. - sorterar på ett
_id
fält som lagrarObjectId
datatyper är en nära motsvarighet till sortering efter skapelsetid.
Vi har sett ObjectIds i exemplen hittills, och de kommer att se ut så här:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d19")}
Obs :ObjectId-värden bör öka med tiden, men de är inte nödvändigtvis monotona. Detta beror på att de:
- Innehåller endast en sekunds tidsmässig upplösning, så värden skapade inom samma sekund har inte garanterad ordning
- värden genereras av klienter, som kan ha olika systemklockor
Boolean
MongoDB har den ursprungliga Boolean
datatyp för att lagra sanna och falska värden inom en samling. Boolean
i MongoDB kan representeras enligt följande:
Type | Number | Alias | ------------------ | ------ | ------------ | Boolean | 8 | "bool" |
Infoga ett dokument med en Boolean
datatypen kommer att se ut ungefär så här:
db.mytestcoll.insertOne({isCorrect: true, isIncorrect: false}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d21")}
När du sedan söker efter dokumentet kommer resultatet att visas som:
db.mytestcoll.find().pretty(){ "_id" : ObjectId("614b37296a124db40ae74d21") "isCorrect" : true, "isIncorrect" : false}
Reguljärt uttryck
Regular Expression
datatyp i MongoDB tillåter lagring av reguljära uttryck som värdet på ett fält. MongoDB använder PCRE (Perl Compatible Regular Expression) som sitt reguljära uttrycksspråk.
Dess kan representeras på följande sätt:
Type | Number | Alias | ------------------ | ------ | ------- | Regular Expression | 11 | "regex" |
BSON låter dig undvika det typiska "konvertera från sträng"-steget som är vanligt förekommande när du arbetar med reguljära uttryck och databaser. Den här typen kommer att vara mest användbar när du skriver databasobjekt som kräver valideringsmönster eller matchande triggers.
Till exempel kan du infoga Regular Expression
datatyp så här:
db.mytestcoll.insertOne({exampleregex: /tt/}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d16")}db.mytestcoll.insertOne({exampleregext:/t+/}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d17")}
Denna sekvens av uttalanden kommer att lägga till dessa dokument till din samling. Du kan sedan fråga din samling för att hitta de infogade dokumenten:
db.mytestcoll.find().pretty(){ _id: ObjectId("614b37296a124db40ae74d16"), exampleregex: /tt/, _id: ObjectId("614b37296a124db40ae74d17"), exampleregex: /t+/ }
De reguljära uttrycksmönstren lagras som regex och inte som strängar. Detta gör att du kan fråga efter en viss sträng och få returnerade dokument som har ett reguljärt uttryck som matchar den önskade strängen.
JavaScript (utan omfattning)
Ungefär som det tidigare nämnda Regular Expression
datatyp, tillåter BSON MongoDB att lagra JavaScript-funktioner utan räckvidd som sin egen typ. JavaScript
typ kan kännas igen enligt följande:
Type | Number | Alias | ------------------ | ------ | ------------ | JavaScript | 13 | "javascript" |
Lägga till ett dokument till din samling med JavaScript
datatypen kommer att se ut ungefär så här:
db.mytestcoll.insertOne({jsCode: "function(){var x; x=1}"}){ "acknowledged": true, "insertedId": ObjectId("614b37296a124db40ae74d122")}
Denna funktion låter dig lagra JavaScript-funktioner i dina MongoDB-samlingar om det behövs för ett visst användningsfall.
Obs :Med MongoDB version 4.4 och senare, en alternativ JavaScript-typ, JavaScript with Scope
datatyp, har fasats ut
Slutsats
I den här artikeln har vi täckt de flesta vanliga datatyper som är användbara när du arbetar med MongoDB-databaser. Det finns ytterligare typer som inte uttryckligen tas upp i den här guiden som kan vara till hjälp beroende på användningsfallet. Att komma igång genom att känna till dessa typer täcker de flesta användningsfall. Det är en stark grund för att börja modellera din MongoDB-databas.
Det är viktigt att veta vilka datatyper som är tillgängliga för dig när du använder en databas så att du använder giltiga värden och arbetar på data med förväntade resultat. Det finns risker som du kan stöta på utan att skriva in din data ordentligt, som visas i Double
kontra Decimal128
träning. Det är viktigt att tänka på detta innan du bestämmer dig för en viss typ.
Om du är intresserad av att kolla in Prisma med en MongoDB-databas kan du kolla in dataanslutningsdokumentationen.