Komma igång med MongoDB - Del 2

Klar för att fortsätta att lära sig om MongoDB, en av de coolaste teknikerna för webbutvecklare? I den här andra delen av serien fortsätter vi från grunderna till avancerade frågor - med villkorade operatörer - och MapReduce.


Steg utöver grunderna

Tidigare omfattade vi grunderna och hur man började med mongoDB, en av de absolut bästa raserna av NoSQL-implementeringarna. Vi tittade på hur man installerar den, skapar en grundläggande databas och utför sedan de grundläggande operationerna på den:

  • Sök
  • uppdatering
  • radera

Utöver detta började vi titta på hur man började interagera med mongoDB på ett mer kraftfullt sätt, genom att använda selektorer. Selektörer ger oss möjlighet att ha mycket mer finkorrigerad kontroll och att gräva ganska djupt för att hitta de data som vi verkligen vill ha.

Nu är det bra och bra att komma igång med, men när du vill skriva en riktig applikation behöver du gå mycket längre. Jo, det här är fortfarande ett komma igång serien, men jag vill bli upphetsad om möjligheterna att arbeta på ett dokumentorienterat sätt. Jag vill entusera dig för att ta den här fantastiska tekniken och göra den till din egen och använda den så kraftfullt som möjligt för att göra fantastiska applikationer.

Idag kommer vi att expandera på frågor från förra gången och lära oss två viktiga aspekter av mongoDB:

  • Avancerade frågor
  • MapReduce

Avancerade frågor

Tidigare tittade vi på grundläggande frågor och introducerades till väljare. Nu ska vi komma in i mer avancerade frågor, genom att bygga på det föregående arbetet på två viktiga sätt:

  • Villkorliga operatörer
  • Vanliga uttryck

Var och en av dessa ger oss successivt mer finkorrigerad kontroll över de frågor vi kan skriva och följaktligen den information som vi kan extrahera från våra mongoDB-databaser.

Villkorliga operatörer

Villkorerade operatörer är, som namnet antyder, operatörer att samla in frågor som avgränser villkoren som förfrågan måste matcha när data extraheras från databasen. Det finns ett antal av dem, men idag kommer jag att fokusera på 9 viktiga. Dessa är:

  • $ lt - Värdet måste vara mindre än det villkorliga
  • $ gt - Värdet måste vara större än det villkorliga
  • $ lte - Värdet måste vara mindre än eller lika med villkoret
  • $ GTE - Värdet måste vara större än eller lika med villkoret
  • $ i - Värdet måste vara i en uppsättning villkor
  • $ nin - Värdet får INTE vara i en uppsättning villkor
  • $ inte - värdet måste vara lika med en villkorlig

Låt oss titta på var och en i tur och ordning. Öppna din terminal och gör dig redo att använda originaldatabasen från den första delen i denna serie (förändringar). För att göra denna handledning enklare kommer vi att göra en liten ändring i databasen. Vi ska ge varje dokument i vår samling ett åldersattribut. För att göra det, kör följande modifieringsfråga:

 db.nettuts.update ("_ id": ObjectId ("4ef224be0fec2806da6e9b27"), "$ set": "ålder": 18); db.nettuts.update ("_ id": ObjectId ("4ef224bf0fec2806da6e9b28"), "$ set": "ålder": 45); db.nettuts.update ("_ id": ObjectId ("4ef224bf0fec2806da6e9b29"), "$ set": "ålder": 65); db.nettuts.update ("_ id": ObjectId ("4ef224bf0fec2806da6e9b2a"), "$ set": "ålder": 43); db.nettuts.update ("_ id": ObjectId ("4ef224bf0fec2806da6e9b2b"), "$ set": "ålder": 22); db.nettuts.update ("_ id": ObjectId ("4ef224bf0fec2806da6e9b2c"), "$ set": "ålder": 45); db.nettuts.update ("_ id": ObjectId ("4ef224bf0fec2806da6e9b2d"), "$ set": "ålder": 33);

Allt är bra, du kan köra en "hitta alla" och du får följande utdata:

 db.nettuts.find (); "_id": ObjectId ("4ef224be0fec2806da6e9b27"), "ålder": 18, "dob": "21/04/1978", "första": "matthew", "gender": "m", "hair_colour" "brown", "last": "setter", "nationalitet": "australien", "ockupation": "utvecklare" "_id": ObjectId ("4ef224bf0fec2806da6e9b28"), "ålder": 45, "dob" "26/03/1940", "första": "james", "gender": "m", "hair_colour": "brown", "last": "caan", "nationalitet" ":" skådespelare " " _id ": ObjectId (" 4ef224bf0fec2806da6e9b29 ")," ålder ": 65," dob ":" 03/06/1925 "," först ":" arnold "," gender " "," hår ":" brunt "," sista ":" schwarzenegger "," nationalitet ":" amerikansk "," ockupation ":" skådespelare " " _id ": ObjectId (" 4ef224bf0fec2806da6e9b2a ")," ålder " 43, "dob": "21/04/1978", "första": "tony", "kön": "m", "hair_colour": "brown", "last": "curtis", "nationalitet" "amerikansk", "ockupation": "utvecklare" "_id": ObjectId ("4ef224bf0fec2806da6e9b2b"), "ålder": 22, "dob": "22/11/1958", "först": "jamie lee" , "kön": "f", "hår" "färg": "brun", "sista": "curtis", "nationalitet": "amerikansk", "ockupation": "skådespelare" "_id": ObjectId ("4ef224bf0fec2806da6e9b2c"), "ålder" dob ":" 14/03/1933 "," först ":" michael "," gender ":" m "," hair_colour " , "yrke": "skådespelare" "_id": ObjectId ("4ef224bf0fec2806da6e9b2d"), "ålder": 33, "dob": "09/12/1934", "först": "judi" : "f", "hair_colour": "white", "last": "dench", "nationality": "engelska", "ockupation": "skådespelerska")

$ Lt / $ lte

Låt oss nu hitta alla aktörer som är mindre än 40. För att göra det, kör följande fråga:

 db.nettuts.find ("age": "$ lt": 40);

När du har kört den frågan ser du följande utdata:

 "_id": ObjectId ("4ef224be0fec2806da6e9b27"), "ålder": 18, "dob": "21/04/1978", "första": "matthew", "gender": "m", "hair_colour" "brown", "last": "setter", "nationalitet": "australiensisk", "ockupation": "utvecklare" "_id": ObjectId ("4ef224bf0fec2806da6e9b2b"), "ålder": 22, "dob" "Jamie lee", "gender": "f", "hair_colour": "brown", "last": "curtis", "nationalitet" ockupation ":" skådespelare " " _id ": ObjectId (" 4ef224bf0fec2806da6e9b2d ")," ålder ": 33," dob ":" 09/12/1934 "," första ":" judi " f "," hair_colour ":" white "," last ":" dench "," nationality ":" engelska "," ockupation ":" skådespelerska ")

Vad sägs om dem som är mindre än 40 inklusive? Kör följande fråga för att returnera resultatet:

 db.nettuts.find ("age": "$ lte": 40);

Detta returnerar följande lista:

 "_id": ObjectId ("4ef224be0fec2806da6e9b27"), "ålder": 18, "dob": "21/04/1978", "första": "matthew", "gender": "m", "hair_colour" "brown", "last": "setter", "nationalitet": "australiensisk", "ockupation": "utvecklare" "_id": ObjectId ("4ef224bf0fec2806da6e9b2b"), "ålder": 22, "dob" "Jamie lee", "gender": "f", "hair_colour": "brown", "last": "curtis", "nationalitet" ockupation ":" skådespelare " " _id ": ObjectId (" 4ef224bf0fec2806da6e9b2d ")," ålder ": 33," dob ":" 09/12/1934 "," första ":" judi " f "," hair_colour ":" white "," last ":" dench "," nationality ":" engelska "," ockupation ":" skådespelerska ")

$ Gt / GTE $

Låt oss nu hitta alla aktörer som är äldre än 47. Kör följande fråga för att hitta den listan:

 db.nettuts.find ('age': '$ gt': 47);

Du får då följande utmatning:

 "_id": ObjectId ("4ef224bf0fec2806da6e9b29"), "ålder": 65, "dob": "03/06/1925", "första": "arnold", "gender": "m", "hair_colour" "brunt", "sista": "schwarzenegger", "nationalitet": "amerikan", "ockupation": "skådespelare")

Vad sägs om inklusive 40?

 db.nettuts.find ('age': '$ gte': 47);

Eftersom det bara finns en person över 47, ändras inte data.

$ I / $ Nin

Vad sägs om att hitta information baserat på en lista med kriterier? Dessa första har varit okej, men utan tvekan ganska trivial. Låt oss nu se för att se vilka av de människor vi har är antingen skådespelare eller utvecklare. Med följande fråga kommer vi att ta reda på det (för att göra det lite lättare att läsa, vi har begränsat nycklarna som returneras till för- och efternamn):

 db.nettuts.find ('occupation': '$ in': ["skådespelare", "utvecklare"], "först": 1, "sista": 1);

Den här frågan ger följande utdata:

 "_id": ObjectId ("4ef224bf0fec2806da6e9b27"), "första": "matthew", "sista": "setter" "_id" ":" caan " " _id ": ObjectId (" 4ef224bf0fec2806da6e9b29 ")," första ":" arnold "," sista ":" schwarzenegger " " _id ": ObjectId (" 4ef224bf0fec2806da6e9b2a ")," först " "tjej", "sista": "curtis" "_id": ObjectId ("4ef224bf0fec2806da6e9b2b"), "först": "jamie lee", "sist": "curtis" "_id": ObjectId ("4ef224bf0fec2806da6e9b2c ")," först ":" michael "," sista ":" caine "

Du kan se att vi kan få invers av detta med hjälp av $ ninprecis som enkelt.

Låt oss göra det lite roligare och kombinera några av operatörerna. Låt oss säga att vi vill leta efter alla människor, som är antingen manliga eller utvecklare, de är mindre än 40 år.

Nu är det lite av en muntlig, men med de operatörer som vi har använt hittills - ganska lätt uppnåeliga. Låt oss arbeta igenom det och du kommer att se. Ta en titt på frågan nedan:

 db.nettuts.find ($ eller: ["gender": "m", "occupation": "developer"], "ålder": "$ gt": 40, "först": 1 , "sista": 1, "ockupation": 1, "dob": 1);

Du kan se att vi har bestämt att könet kan vara man eller ockupationen kan vara en utvecklare i $ eller skick och sedan lagt till en och Åldern är större än 4 år.

För det får vi följande resultat:

 "_id": ObjectId ("4ef22e522893ba6797bf8cb6"), "första": "matthew", "last": "setter", "dob": "21/04/1978", "ockupation" _id ": ObjectId (" 4ef22e522893ba6797bf8cb9 ")," först ":" tony "," sista ":" curtis "," dob ":" 21/04/1978 "," ockupation ":" utvecklare "

Vanliga uttryck

Nu är jag säker på att du inte kommer att bli nöjd med just detta. Jag lovade dig lite mer komplexitet och avancerad funktionalitet. Så låt oss gå in på att använda några vanliga uttryck. Låt oss säga att vi vill hitta de användare som har ett förnamn som börjar med 'ma' eller 'till' och vars efternamn börjar med 'se' eller 'de'. Hur skulle vi göra det?

Ta en titt på följande fråga med ett vanligt uttryck:

 db.nettuts.find ("first": / (ma | till) * / i, "sista": / (se | de) / i);

Med tanke på detta kommer resultaten att vara:

 "_id": ObjectId ("4ef22e522893ba6797bf8cb6"), "första": "matthew", "sista": "setter", "dob": "21/04/1978", "gender": "m", "hair_colour "ockupation": "utvecklare", "nationalitet": "australian" "_id": ObjectId ("4ef22e532893ba6797bf8cbc"), "först": "judi", "sista" "dob": "09/12/1934", "kön": "f", "hair_colour": "white", "occupation": "skådespelerska", "nationalitet": "engelska")

Låt oss titta på den frågan lite närmare. För det första utför vi en regex på förnamnet.

 "första": / (ma | till) * / i

//jag indikerar att vi utför en fallinsensiv regex.

(Ma | till) * indikerar att början på förnamnsträngen måste vara antingen 'ma' eller 'till'.

Om du inte är bekant, kommer * i slutet att matcha allt efter det. Så när du sätter ihop matchar vi förnamn som har antingen "ma" eller "till" i början av dem. I regex för efternamn kan du se att vi har gjort samma sak, men för efternamnet.

Inte riktigt säker? Låt oss försöka en annan. Vad sägs om att kombinera den med en av de villkorliga operatörerna. Låt oss säga att vi vill hitta alla människor med förnamnet James eller Jamie som är amerikanska kvinnliga aktörer. Hur skulle vi göra det? Tja, låt oss se hur vi skulle göra det nedan:

 db.nettuts.find ("first": / (jam? e *) * / jag, "gender": "f", "occupation": "skådespelare", "nationalitet": "amerikansk");

Regex ovan kommer att matcha kombinationer som: james, jamie, jamee etc. Frågetecknet kommer att matcha ett tecken, oavsett a-z, A-Z eller 0-9. Då, som tidigare, matchar * allt annat som kommer efter "e". Därifrån använder vi de villkorade operatörerna från tidigare för att ytterligare begränsa resultaten som kommer tillbaka. Det bör noteras att när vi använder den otillräckliga operatören, jag, kommer frågorna inte att använda ett index. Men i det här exemplet är det bra.

Resultatet av frågan ovan är:

 "_id": ObjectId ("4ef22e522893ba6797bf8cba"), "först": "jamie lee", "sista": "curtis", "dob": "22/11/1958" hair_colour ":" brown "," occupation ":" skådespelare "," nationalitet ":" amerikansk "

MapReduce

MapReduce är den stora pappan av dataanalys. Om du inte har hört talas om det, är MapReduce en process där aggregering av data kan delas upp och odlas över ett kluster av datorer för att minska den tid det tar för att bestämma ett aggregerat resultat på en uppsättning data.

Den består av två delar: Karta och Minska. Kartan skapar de jobb som sedan kan odlas ut till arbetarknoderna för att köra Reduce-komponenten. Minska sedan beräknar svaret för den bit av arbete som odlades ut till det och returnerar resultatet som kan kombineras med de andra bitarna för att bilda det slutliga svaret.

Om du vill ha en mer specifik beskrivning, här är vad Wikipedia har att säga om det:

MapReduce är ett ramverk för bearbetning av högt distribuerbara problem över stora dataset med ett stort antal datorer (noder), gemensamt kallat ett kluster (om alla noder använder samma hårdvara) eller ett rutnät (om noderna använder annan hårdvara). Beräkningsbehandling kan ske på data som lagras antingen i ett filsystem (ostrukturerad) eller i en databas (strukturerad).

"Karta" steg: Masternoden tar ingången, skiljer den upp i mindre delproblem och distribuerar dem till arbetarknoder. En arbetarknut kan göra det i sin tur, vilket leder till en trädstruktur med flera nivåer. Arbetstagarens nod hanterar det mindre problemet och skickar svaret tillbaka till dess huvudnod.

"Minska" steg: Masternoden samlar sedan in svaren på alla delproblem och kombinerar dem på något sätt för att bilda produktionen - svaret på det problem som det ursprungligen försökte lösa.

Exempel MapReduce

Låt oss titta på ett enkelt exempel. Vi ska analysera vårt enkla dataset och hitta det totala antalet kvinnor i gruppen. Visst är detta ett mycket förenklat exempel, men det kommer att ligga till grund för förståelse, praktiskt taget hur MapReduce fungerar.

Kartfunktionen

Här ska vi skapa en kartfunktion som aggregerar informationen i vårt dataset efter personens kön och ger ett antal av 1 för var och en av dem.

 var map = funktion () emit (kön: this.gender, count: 1); 

Detta kommer att returnera produkt som liknar följande:

 'f': 1

Reduktionsfunktionen

Vår reduceringsfunktion kommer att ta utmatningen från kartfunktionen och använda den för att hålla en löpande summa av räkningen för varje kön. Ta en titt på reduceringsfunktionen nedan.

 var reducera = funktion (nyckel, värden) var result = count: 0; values.forEach (funktion (värde) result.count + = value.count;) returresultat; 

Körning av MapReduce

Nu sätter vi dem ihop genom att ringa MapReduce funktion i vår nuvarande databas. Vi passerar i Karta och minska variabler som vi skapade tidigare genom att ringa vår Karta och minska funktioner och ange namnet på samlingen som resultatet ska lagras i; I detta fall 'kön'. Bara för att upprepa, är resultatet av att ringa MapReduce-funktionen en samling i vår nuvarande databas; att vi kan iterera över precis som vi skulle någon annan samling. Ta en titt på koden nedan:

 var res = db.nettuts.mapReduce (karta, minska, ut: 'kön');

Visar utmatningen

När Map-Reduce är klar kan vi komma åt det som en vanlig samling genom att köra hittafungera på det som vi gör nedan.

 db.gender.find (); "_id": "kön": "f", "värde": "count": 2 "_id": "gender": "m", "value" : 5

Här har vi nu en löpande total per kön; 2 för honor och 5 för män - vilket hör samman med vår dataset. Men vad händer om vi ville filtrera av kvinnor i gruppen. Tja, inte mycket till det. Vi behöver bara använda frågeklausulen så att vi kan göra det. Lycklig för oss, det kommer att se bekant. Ta en titt på frågan nedan.

 var res = db.nettuts.mapReduce (karta, minska, ut: "kön", fråga: "gender": "f");

Nu när vi visar utmatningen ser det ut som nedan:

 db.gender.find (); "_id": "gender": "f", "value": "count": 2

Det finns ett antal andra parametrar som du kan skicka till kartanReduce-funktionen för att ytterligare anpassa utmatningen.

  • sortera - sortera utmatningen returnerad
  • begränsa - begränsa antalet återkomna resultat
  • ut - namnet på samlingen för att lagra resultaten i
  • avsluta - Ange en funktion som ska köras efter att reduktionsprocessen är klar
  • omfattning - specificera variabler som kan användas i kartan, minska och slutföra funktionsomfånget
  • jsMode - Undvik ett mellansteg (mellan kart och minska) för att konvertera tillbaka till JSON-format
  • mångordig - spåra statistik om körprocessen

Avveckling

Detta har varit en virvelvind täckning av några av de mer komplexa ämnena i mongoDB. Men jag hoppas att det har gett dig ännu mer smak av vad som är möjligt genom att använda detta fantastiska verktyg.

Vi har tittat på de villkorade operatörerna: $ lt, $ gt, $ lte, $ gte, $ in, $ nin, $ inte och kör igenom en introduktion till MapReduce. Jag hoppas att du har fått mycket ut av det här och lär dig mer om det stora verktyget som är mongoDB.