För att skapa en relation i MongoDB, antingen bädda in ett BSON-dokument i ett annat eller referera till det från ett annat.
MongoDB-databaser fungerar annorlunda än relationsdatabaser. Detta gäller även för relationer.
I MongoDB kan du skapa en relation med någon av följande två metoder:
- Inbäddade dokument.
- Refererade dokument.
Metoden du använder beror på data och hur du avser att söka efter data.
Inbäddade relationer
Med MongoDB kan du bädda in dokument i dokument. Därför kan ett enda dokument innehålla sina egna relationer.
Faktum är att vi redan skapade en relation med den här metoden när vi först skapade ett dokument.
En-till-en-relation
En en-till-en-relation är där det överordnade dokumentet har ett barn och barnet har en förälder.
En affärsregel kan till exempel säga att en artist bara kan ha en adress och att adressen bara kan tillhöra en artist.
Följande kod skapar en en-till-en-relation, inbäddad i dokumentet.
db.artists.insert( { _id : 2, artistname : "Prince", address : { street : "Audubon Road", city : "Chanhassen", state : "Minnesota", country : "United States" } } )
Resultat:
WriteResult({ "nInserted" : 1 })
En-till-många-relation
En en-till-många relation är där det överordnade dokumentet kan ha många underordnade dokument, men de underordnade dokumenten kan bara ha ett överordnat dokument.
Så en annan affärsregel kan säga att en artist kan ha många album, men ett album kan bara tillhöra en artist.
Genom att köra följande kod skapas en en-till-många-relation:
db.artists.insert( { _id : 3, artistname : "Moby", albums : [ { album : "Play", year : 1999, genre : "Electronica" }, { album : "Long Ambients 1: Calm. Sleep.", year : 2016, genre : "Ambient" } ] } )
Resultat:
WriteResult({ "nInserted" : 1 })
Dokumentreferensrelationer
Du kan använda en dokumentreferens för att skapa en relation. Istället för att bädda in det underordnade dokumentet i det överordnade dokumentet (som vi gjorde ovan), separerar du det underordnade dokumentet i ett eget fristående dokument.
Så vi kunde göra detta:
Overordnat dokument
db.artists.insert( { _id : 4, artistname : "Rush" } )
Barndokument
Vi kommer att infoga 3 underordnade dokument — ett för varje bandmedlem:
db.musicians.insert( { _id : 9, name : "Geddy Lee", instrument : [ "Bass", "Vocals", "Keyboards" ], artist_id : 4 } )
db.musicians.insert( { _id : 10, name : "Alex Lifeson", instrument : [ "Guitar", "Backing Vocals" ], artist_id : 4 } )
db.musicians.insert( { _id : 11, name : "Neil Peart", instrument : "Drums", artist_id : 4 } )
Fråga relationen
Efter att ha infogat ovanstående två dokument kan du använda $lookup
för att utföra en vänster yttre sammanfogning på de två samlingarna.
Detta i kombination med aggregate()
metod och $match
för att ange den specifika artist du är intresserad av, returnerar föräldra- och underordnade dokument i ett.
db.artists.aggregate([ { $lookup: { from: "musicians", localField: "_id", foreignField: "artist_id", as: "band_members" } }, { $match : { artistname : "Rush" } } ]).pretty()
Resultat:
{ "_id" : 4, "artistname" : "Rush", "band_members" : [ { "_id" : 9, "name" : "Geddy Lee", "instrument" : [ "Bass", "Vocals", "Keyboards" ], "artist_id" : 4 }, { "_id" : 10, "name" : "Alex Lifeson", "instrument" : [ "Guitar", "Backing Vocals" ], "artist_id" : 4 }, { "_id" : 11, "name" : "Neil Peart", "instrument" : "Drums", "artist_id" : 4 } ] }
Du kan se att de två första fälten är från artistsamlingen, och resten av det är från musikersamlingen.
Så om du bara frågar efter artistsamlingen själv:
db.artists.find( { artistname : "Rush" } )
Du får bara detta:
{ "_id" : 4, "artistname" : "Rush" }
Ingen relaterad data returneras.
När ska man använda inbäddade dokument vs refererade dokument
Båda metoderna för att skapa relationer har sina för- och nackdelar. Det finns tillfällen du kanske använder inbäddade dokument, och andra gånger använder du refererade dokument.
När ska man använda inbäddade relationer
En av de främsta fördelarna med att använda den inbäddade relationsmetoden är prestanda. När relationen är inbäddad i dokumentet kommer frågor att köras snabbare än om de var spridda över flera dokument. MongoDB behöver bara returnera ett dokument, snarare än att sammanfoga flera dokument för att hämta relationerna. Detta kan ge en rejäl prestandaökning — särskilt när du arbetar med mycket data.
Inbäddade relationer gör det också lättare att skriva frågor. Istället för att skriva komplexa frågor som sammanfogar många dokument via deras unika identifierare, kan du returnera all relaterad data inom en enda fråga.
En annan faktor att tänka på är att MongoDB endast kan säkerställa atomicitet på dokumentnivå. Dokumentuppdateringar till ett enda dokument är alltid atomära, men inte för flera dokument.
När flera användare kommer åt data finns det alltid en chans att två eller flera användare kommer att försöka uppdatera samma dokument med olika data. I det här fallet kommer MongoDB att se till att ingen konflikt uppstår och att endast en uppsättning data uppdateras åt gången. MongoDB kan inte säkerställa detta över flera dokument.
Så generellt sett kan inbäddade relationer användas i de flesta fall, så länge som dokumentet förblir inom storleksgränsen (16 megabyte i skrivande stund) och/eller dess kapslingsgräns (100 nivåer djup vid skrivande stund).
Inbäddade relationer är dock inte lämpliga för alla tillfällen. Det kan finnas situationer där det är mer meningsfullt att skapa ett dokument som refereras till.
När ska man använda refererade relationer
För data som behöver upprepas i många dokument kan det vara bra att ha dem i sitt eget separata dokument. Detta kan minska antalet fel och hjälpa till att hålla data konsekventa (samtidigt som man har i åtanke att uppdateringar av flera dokument inte är atomära).
Med exemplet ovan kan en musiker vara medlem (eller före detta medlem) i många band. Vissa kanske också producerar album för andra artister, undervisar studenter, driver kliniker, etc. Dessutom kan mycket data lagras mot varje musiker. Så att ha ett separat dokument för varje musiker är meningsfullt i det här fallet.
Om du tror att dina inbäddade dokument kan överskrida filstorleksgränsen som fastställts av MongoDB, måste du lagra vissa data i separata dokument.