sql >> Database teknologi >  >> NoSQL >> MongoDB

Sammenkædning og oprettelse af MongoDB-forbindelser ved hjælp af SQL:Del 2

JOIN er en af ​​de vigtigste særskilte funktioner mellem SQL- og NoSQL-databaser. I SQL-databaser kan vi udføre en JOIN mellem to tabeller inden for samme eller forskellige databaser. Dette er dog ikke tilfældet for MongoDB, da det tillader JOIN-operationer mellem to samlinger i samme database.

Den måde, data præsenteres på i MongoDB, gør det næsten umuligt at relatere dem fra en samling til en anden, undtagen når du bruger grundlæggende script-forespørgselsfunktioner. MongoDB denormaliserer enten data ved at gemme relaterede elementer i et separat dokument, eller det relaterer data i et andet separat dokument.

Man kunne relatere disse data ved at bruge manuelle referencer såsom _id-feltet for et dokument, der er gemt i et andet dokument som reference. Ikke desto mindre er man nødt til at lave flere forespørgsler for at hente nogle nødvendige data, hvilket gør processen lidt trættende.

Vi beslutter os derfor for at bruge JOIN-konceptet, som letter relationen mellem dataene. JOIN-operationen i MongoDB opnås ved brug af $lookup-operatoren, som blev introduceret i version 3.2.

$lookup operator

Hovedideen bag JOIN-konceptet er at få sammenhæng mellem data i en samling til en anden. Den grundlæggende syntaks for $lookup operator er:

{ $lookup:{ fra:, localField:, fremmedField:, som: }}

Med hensyn til SQL-viden ved vi altid, at resultatet af en JOIN-operation er en separat række, der forbinder alle felter fra den lokale og udenlandske tabel. For MongoDB er dette et andet tilfælde, idet resultatdokumenterne tilføjes som en række lokale indsamlingsdokumenter. Lad os for eksempel have to samlinger; 'studerende' og 'enheder'

studerende

{"_id" :1,"name" :"James Washington","age" :15.0,"grade" :"A","score" :10.5}{"_id" :2," name" :"Clinton Ariango","alder" :14.0,"grade" :"B","score" :7.5}{"_id" :3,"name" :"Mary Muthoni","alder" :16.0, "grade" :"A","score" :11,5} 

Enheder

{"_id" :1,"Maths" :"A","English" :"A","Science" :"A","Historie" :"B"}{"_id" :2,"Maths" :"B","English" :"B","Science" :"A","Historie" :"B"}{"_id" :3,"Maths" :"A"," English" :"A","Science" :"A","Historie" :"A"} 

Vi kan hente elevernes enheder med respektive karakterer ved hjælp af $lookup-operatoren med JOIN-tilgangen .i.e

db.getCollection('students').aggregate([{$lookup:{ from:"units", localField:"_id", foreignField :"_id", as:"studentUnits" }}])  

Hvilket vil give os resultaterne nedenfor:

{"_id" :1,"name" :"James Washington","age" :15,"grade" :"A","score" :10.5, "studentUnits" :[{"_id " :1,"Maths" :"A","English" :"A","Science" :"A","Historie" :"B"}]}{"_id" :2,"name" :" Clinton Ariango","age" :14,"grade" :"B","score" :7.5, "studentUnits" :[{"_id" :2,"Maths" :"B","English" :"B ","Science" :"A","Historie" :"B"}]}{"_id" :3,"name" :"Mary Muthoni","alder" :16,"grade" :"A", "score" :11,5, "studentUnits" :[{"_id" :3,"Maths" :"A","English" :"A","Science" :"A","Historie" :"A"} ]} 

Som nævnt før, hvis vi laver en JOIN ved hjælp af SQL-konceptet, vil vi blive returneret med separate dokumenter i Studio3T-platformen .i.e

VÆLG * FRA studerende INNER JOIN-enheder PÅ studerende._id =units._id 

Er en ækvivalent til

db.getCollection("students").aggregate( [ { "$project" :{ "_id" :NumberInt(0), "students" :"$$ROOT" } }, { "$lookup " :{ "localField" :"students._id", "from" :"units", "foreignField" :"_id", "as" :"units" } }, { "$unwind" :{ "sti" :"$units", "preserveNullAndEmptyArrays" :false } } ]); 

Ovenstående SQL-forespørgsel vil returnere resultaterne nedenfor:

{ "students" :{"_id" :NumberInt(1),"name" :"James Washington","age" :15.0,"grade" :"A","score" :10.5} , "units" :{"_id" :NumberInt(1),"Maths" :"A","English" :"A","Science" :"A","Historie" :"B"}}{ " students" :{"_id" :NumberInt(2), "name" :"Clinton Ariango","age" :14.0,"grade" :"B","score" :7.5 }, "units" :{"_id" " :NumberInt(2),"Maths" :"B","English" :"B","Science" :"A","Historie" :"B"}}{ "students" :{"_id" :NumberInt(3),"name" :"Mary Muthoni","age" :16.0,"grade" :"A","score" :11.5},"units" :{"_id" :NumberInt(3)," Maths" :"A","English" :"A","Science" :"A","Historie" :"A"}} 

Ydeevnens varighed vil naturligvis være afhængig af strukturen af ​​din forespørgsel. For eksempel, hvis du har mange dokumenter i den ene samling frem for den anden, bør du foretage sammenlægningen fra samlingen med færre dokumenter og derefter slå op i den med flere dokumenter. På denne måde er et opslag for det valgte felt fra den mindre dokumentsamling ganske optimalt og tager mindre tid end at lave flere opslag for et valgt felt i samlingen med flere dokumenter. Det er derfor tilrådeligt at sætte den mindre samling først.

For en relationel database er rækkefølgen af ​​databaserne ligegyldig, da de fleste SQL-fortolkere har optimeringsprogrammer, som har adgang til ekstra information til at beslutte, hvilken der skal være først.

I tilfælde af MongoDB skal vi bruge et indeks for at lette JOIN-operationen. Vi ved alle, at alle MongoDB-dokumenter har en _id-nøgle, som for en relationel DBM kan betragtes som den primære nøgle. Et indeks giver en bedre chance for at reducere mængden af ​​data, der skal tilgås udover at understøtte operationen, når det bruges i $lookup fremmednøglen.

I aggregeringspipelinen, for at bruge et indeks, skal vi sikre, at $matchet udføres første trin for at frafiltrere dokumenter, der ikke matcher kriterierne. For eksempel hvis vi ønsker at hente resultatet for eleven med _id feltværdi lig med 1:

vælg * fra elever INNER JOIN units ON students._id =units._id WHERE students._id =1; 

Den tilsvarende MongoDB-kode, du får i dette tilfælde, er:

db.getCollection("students").aggregate([{"$project" :{ "_id" :NumberInt(0), "students" :"$$ROOT" }}, { "$lookup " :{"localField" :"students._id", "from" :"units", "foreignField" :"_id", "as" :"units"} }, { "$unwind" :{ "sti" :"$units","preserveNullAndEmptyArrays" :false } }, { "$match" :{"students._id" :NumberLong(1) }} ]); 

Det returnerede resultat for forespørgslen ovenfor vil være:

{"_id" :1,"name" :"James Washington","age" :15,"grade" :"A","score" :10.5, "studentUnits" :[{"_id " :1,"Maths" :"A","English" :"A","Science" :"A","Historie" :"B"}]} 

Når vi ikke bruger $match-fasen eller rettere ikke på den første fase, hvis vi tjekker med forklaringsfunktionen, vil vi også få COLLSCAN-fasen inkluderet. At lave en COLLSCAN for et stort sæt dokumenter vil generelt tage meget tid. Vi beslutter os dermed for at bruge et indeksfelt, som i forklaringsfunktionen kun involverer IXSCAN-stadiet. Sidstnævnte har en fordel, da vi tjekker et indeks i dokumenterne og ikke scanner alle dokumenterne igennem; det vil ikke tage lang tid at returnere resultaterne. Du kan have en anden datastruktur som:

{ "_id" :NumberInt(1), "grades" :{"Maths" :"A", "English" :"A", "Science" :"A", "Historie" :" B" }} 

Vi ønsker måske at returnere karaktererne som forskellige enheder i et array i stedet for et helt indlejret karakterfelt.

Efter at have skrevet SQL-forespørgslen ovenfor, skal vi ændre den resulterende MongoDB-kode. For at gøre det skal du klikke på kopiikonet til højre som nedenfor for at kopiere aggregeringskoden:

Gå derefter til fanen sammenlægning, og i den præsenterede rude er der et indsæt-ikon, klik på det for at indsætte koden.

Klik på $match-rækken og derefter den grønne op-pil for at flytte scenen til toppen som den første fase. Du skal dog først oprette et indeks i din samling som:

db.students.createIndex( { _id:1 }, { name:studentId }) 

Du får kodeeksemplet nedenfor:

db.getCollection("students").aggregate( [{ "$match" :{"_id" :1.0}}, { "$project" :{"_id" :NumberInt(0)," students" :"$$ROOT"}}, { "$lookup" :{"localField" :"students._id","from" :"units","foreignField" :"_id","as" :"units" "}}, { "$unwind" :{"path" :"$units", "preserveNullAndEmptyArrays" :false}} ] 
Severalnines Bliv en MongoDB DBA - Bring MongoDB to ProductionFå flere oplysninger om, hvad du skal vide for at implementere, overvåge, administrere og skalere MongoDBDownload gratis

Med denne kode får vi resultatet nedenfor:

{ "students" :{"_id" :NumberInt(1), "name" :"James Washington","age" :15.0,"grade" :"A", "score" :10.5} , "units" :{"_id" :NumberInt(1), "grades" :{"Maths" :"A", "English" :"A", "Science" :"A", "Historie" :"B "}}} 

Men alt, hvad vi behøver, er at have karaktererne som en separat dokumentenhed i det returnerede dokument og ikke som ovenstående eksempel. Vi vil derfor tilføje $addfields-stadiet og derfor koden som nedenfor.

db.getCollection("students").aggregate( [{ "$match" :{"_id" :1.0}}, { "$project" :{"_id" :NumberInt(0)," students" :"$$ROOT"}}, { "$lookup" :{"localField" :"students._id","from" :"units","foreignField" :"_id","as" :"units" "}}, { "$unwind" :{"path" :"$units", "preserveNullAndEmptyArrays" :false}}, { "$addFields" :{"units" :"$units.grades"} }] 

De resulterende dokumenter vil derefter være:

{"students" :{"_id" :NumberInt(1), "name" :"James Washington", "grade" :"A","score" :10.5}, "units" :{ "Maths" :"A", "English" :"A", "Science" :"A", "Historie" :"B"}} 

De returnerede data er ret pæne, da vi har fjernet indlejrede dokumenter fra enhedernes samling som et separat felt.

I vores næste selvstudie skal vi se på forespørgsler med flere joinforbindelser.


  1. Mongodb summer størrelsen af ​​matrixfelter

  2. Brug af StackExchange.Redis i en ASP.NET Core Controller

  3. Redis - Fremme en slave til at master manuelt

  4. JSON.NET cast-fejl ved serialisering af Mongo ObjectId