brug af joinforbindelser i MongoDB Noskl databaser

brug af $opslag med Noskl

tak til Julian Mott for venligt at hjælpe med at gennemgå denne artikel.

en af de største forskelle mellem databaserne er JOIN. I relationsdatabaser kan du kombinere rækker fra to eller flere tabeller ved hjælp af et fælles felt mellem dem. Hvis du f. eks. har tabeller på books og publishers, kan du skrive:

SELECT book.title, publisher.nameFROM bookLEFT JOIN book.publisher_id ON publisher.id;

med andre ord har tabellen book et publisher_id felt, der refererer til feltet id i tabellen publisher.

dette er praktisk, da en enkelt udgiver kunne tilbyde tusindvis af bøger. Hvis vi nogensinde har brug for at opdatere en udgivers detaljer, kan vi ændre en enkelt post. Dataredundans minimeres, da vi ikke behøver at gentage udgiveroplysningerne for hver bog. Teknikken er kendt som normalisering.

databaserne tilbyder en række normaliserings-og begrænsningsfunktioner for at sikre, at relationer opretholdes.

Noskl == ingen deltage?

ikke altid …

Dokumentorienterede databaser som MongoDB er designet til at gemme denormaliserede data. Ideelt set bør der ikke være noget forhold mellem samlinger. Hvis de samme data kræves i to eller flere dokumenter, skal de gentages.

dette kan være frustrerende, da der er få situationer, hvor du aldrig har brug for relationelle data. Heldigvis introducerer MongoDB 3.2 en ny $lookup operatør, der kan udføre en venstre-ydre-JOIN-lignende operation på to eller flere samlinger. Men der er en fangst …

MongoDB Aggregation

$lookup er kun tilladt i aggregeringsoperationer. Tænk på disse som en pipeline af operatører, der forespørger, filtrerer og grupperer et resultat. Udgangen fra en operatør bruges som input til den næste.

aggregering er vanskeligere at forstå end enklere find forespørgsler og vil generelt køre langsommere. De er dog kraftfulde og en uvurderlig mulighed for komplekse søgeoperationer.

aggregering forklares bedst med et eksempel. Antag, at vi opretter en social medieplatform med en user samling. Det gemmer hver brugers detaljer i separate dokumenter. For eksempel:

{ "_id": ObjectID("45b83bda421238c76f5c1969"), "name": "User One", "email: "[email protected]", "country": "UK", "dob": ISODate("1999-09-13T00:00:00.000Z")}

vi kan tilføje så mange felter som nødvendigt, men alle MongoDB-dokumenter kræver et _id – felt, der har en unik værdi. _id svarer til en primær nøgle og indsættes automatisk, hvis det er nødvendigt.

vores sociale netværk kræver nu en post samling, der gemmer adskillige indsigtsfulde opdateringer fra brugere. Dokumenterne gemmer teksten, datoen, en vurdering og en henvisning til den bruger, der skrev den i et user_id – felt:

{ "_id": ObjectID("17c9812acff9ac0bba018cc1"), "user_id": ObjectID("45b83bda421238c76f5c1969"), "date: ISODate("2016-09-05T03:05:00.123Z"), "text": "My life story so far", "rating": "important"}

vi vil nu vise de sidste tyve indlæg med en” vigtig ” vurdering fra alle brugere i omvendt kronologisk rækkefølge. Hvert returneret dokument skal indeholde teksten, tidspunktet for indlægget og den tilknyttede brugers navn og land.

MongoDB-aggregatforespørgslen er bestået en række rørledningsoperatører, der definerer hver operation i rækkefølge. Først skal vi udtrække alle dokumenter fra post samlingen, som har den korrekte vurdering ved hjælp af $match filteret:

{ "$match": { "rating": "important" } }

vi skal nu sortere de matchede elementer i omvendt dato rækkefølge ved hjælp af $sort operatoren:

{ "$sort": { "date": -1 } }

da vi kun kræver tyve indlæg, kan vi anvende en $limit fase, så MongoDB behøver kun at behandle data, vi ønsker:

{ "$limit": 20 }

vi kan nu tilslutte data fra user samlingen ved hjælp af den nye $lookup operatør. Det kræver et objekt med fire parametre:

  • localField: opslagsfeltet i inputdokumentet
  • from: samlingen til at deltage
  • foreignField: feltet til opslag i from samlingen
  • as: navnet på outputfeltet.

vores operatør er derfor:

{ "$lookup": { "localField": "user_id", "from": "user", "foreignField": "_id", "as": "userinfo"} }

dette vil skabe et nyt felt i vores output med navnet userinfo. Den indeholder et array, hvor hver værdi matcher user – dokumentet:

"userinfo": 

vi har et en-til-en-forhold mellem post.user_id og user._id, da et indlæg kun kan have en forfatter. Derfor vil vores userinfo array kun indeholde en vare. Vi kan bruge $unwind operatoren til at dekonstruere den til et underdokument:

{ "$unwind": "$userinfo" }

udgangen konverteres nu til et mere praktisk format, som kan få yderligere operatører anvendt:

"userinfo": { "name": "User One", "email: "[email protected]", …}

endelig kan vi returnere teksten, tidspunktet for indlægget, brugerens navn og land ved hjælp af et $project trin i rørledningen:

{ "$project": { "text": 1, "date": 1, "userinfo.name": 1, "userinfo.country": 1} }

at sætte det hele sammen

vores endelige samlede forespørgsel matcher indlæg, sorterer i rækkefølge, begrænser de seneste tyve elementer, slutter sig til brugerdata, flader brugerarrayet og returnerer kun nødvendige felter. Den fulde kommando:

db.post.aggregate();

resultatet er en samling på op til tyve dokumenter. Eksempel:

fantastisk! Jeg kan endelig skifte til nos!

MongoDB $lookup er nyttigt og kraftfuldt, men selv dette grundlæggende eksempel kræver en kompleks samlet forespørgsel. Det er ikke en erstatning for den mere kraftfulde JOIN-klausul, der tilbydes i CCL. MongoDB tilbyder heller ikke begrænsninger; hvis et user dokument slettes, forbliver forældreløse post dokumenter.

ideelt set bør operatøren $lookup kræves sjældent. Hvis du har brug for det meget, bruger du muligvis den forkerte datalager …

hvis du har relationsdata, skal du bruge en relationsdatabase!

når det er sagt, $lookup er en velkommen tilføjelse til MongoDB 3.2. Det kan overvinde nogle af de mere frustrerende problemer, når du bruger små mængder relationelle data i en database.

You might also like

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.