„this” w JS – kiedy i na co wskazuje
„this” w JavaScripci – kiedy i na co wskazuje
Słowo kluczowe „this” byłe jedną z rzeczy, która dosyć mocna wprawiała mnie w osłupienie, mimo że znałem te słowo kluczowe z języka PHP.
Cały problem powstał ponieważ JavaScript był opraty o kilka języków, m.in. Sheme – język strukturalny w którym „this” jest niepotrzebne i język Java – język obiektowy, który „this” potrzebuje.
JS jest jednocześnie skrukturalny i obiektowy. Dlatego należało jakoś to pogodzić…
Jak postawić aplikacje Node.js na serwerze
Jak postawić aplikacje Node.js na serwerze
W odcinku o „Node.js – kurs w 60 minut” pokazywałem jak postawić aplikację Node na hekoru, czyli platformie, która pozwala uruchomiś swoją aplikację bez konfiguracji servera.
Czasami jednak chcemy postawić Noda na swoim własnym serwerze, np. na VPSie czy dedyku. Dzisiaj właśnie o tym.
Operatory JEDNOargumentowe + – !! w JavaScript
Operatory JEDNOargumentowe + – !!
Uwaga: To co widzisz to nie są popularne w działaniach matematycznych dowanie i odejmowanie.
Są to operatory, które przyjmują jeden argument, czyli ich zastosowanie wygląda następująco:
const numberA = +'34' const numberB = -document.querySelector('input').value const isTrue = !!someObject
W filmie poniżej wyjaśniam jak dokładnie działają:
Immediately-invoked Function Expression IIFE – jak dokładnie działa
Chyba każdy, kto pracował z JavaScriptem widział taki zapis:
(function() { ... })() // lub (() => { ... })()
Immediately-invoked Function Expression (IIFE)
Co więcej, pewnie większość wie do czego taki zapis służy i pewnie większość takiego zapisu używało. Jest to tak zwane Immediately-invoked Function Expression (IIFE), czyli funkcja, która od razu się wywołuje.
Pytanie, ile osób wie dlaczego ten zapis wygląda właśnie tak? Dlaczego potrzebnych jest tyle nawiasów? Po co go stosować? Dzisiaj postaram się odpowiedzieć na wszystkie te pytania.
Czym jest IIFE?
Jak sama nazwa mówi jest to natychmiastowo samowywołująca się funkcja. Czyli funkcja, która wykonuje się od razu. I tyle, nie ma co komplikować.
Dlaczego stosować IIFE a nie zwykłą funkcję?
Skoro jest to funkcja, to dlaczego utrudniamy sobie ten zapis? Przecież coś takiego dałoby się zapisać, np. w taki sposób:
function start() { ... } start()
Zadziałałoby w ten sam sposób i jest czytelniej, prawda? Teoretycznie tak. Zastanówmy się w takim razie, po co w ogóle używać funkcji zamiast napisać kod od razu, omijając funkcję.
Po co w ogóle pisać kod w funkcji?
Powodów jest kilka:
- jeśli mamy kod w funkcji, wiadome jest, że jest on jakoś ze sobą powiązany, że jest to część tego samego skryptu
- kod jest czytelniejszy
- NAJWAŻNIEJSZE: nie zaśmiecamy globalnej przestrzeni nazw. Nazwy zmiennych/funkcji naszego kodu nie będą kolidowały z innymi skryptami, które mogą używać takich samych nazw. Nasz kod jest hermetycznie zamknięty. Tak jakby miał swoje własne środowisko!
Skoro wrzucanie kodu do funkcji ma sens, to dlaczego nie użyć zwykłej funkcji zamiast IIFE?
Dlaczego akurat IIFE?
W przypadku zwykłej funkcji tworzymy jej nazwę a to już prowadzi do potencjalnej kolizji z innymi skryptami. Bo przecież ta nazwa znajdzie się w globalnej przestrzeni, więc jakiś inny skrypt będzie miał taką samą funkcję cała nasza aplikacja przestanie działać.
W przypadku IIFE jest to funkcja anonimowa – nie ma żadnej nazwy. Skoro nie ma nazwy – nie ma mowy o ewentualnej kolizji.
Kolejny plus to zapis, który na początku wydaje się dziwny. Jeśli się lepiej przyjrzeć to takie zapis
(() => { ...kod... })()
jest czytelniejszy, bezpieczniejszy i szyby do napisania niż
function someFunction() { ...kod... }
someFunction()
Należy tylko zrozumieć dlaczego ten zapis wygląda tak jak wygląda
Co oznacza (() => { … })(). Dlaczego tyle nawiasów?
Powyższy zapis można rozbić na 2 części
- () => {} – zwykła funkcja strzałkowa, równie dobrze to może być tradycyjna funkcja czyli function() {}
- () – nawias na końcu, czyli uruchomienie funkcji
Okej, wg tego kod wyglądałby tak: () => {}() czyli utworzenie funkcji i od razu jej wywołanie. To sam sens bo przecież IIFE to (anonimowa) funkcja, która od razu się wywołuje.
Jednak wciąż brakuje nawiasu do okoła funkcji.
Błąd parsera
Po próbie wywołania takiego kodu () => {}() zobaczymy błąd:
Uncaught SyntaxError: Unexpected token '(’
Początek jest dobry, można zdefiniować funckję i do niczego jej nie przypisać, ale JS nie spodziewa się ostatniego nawiasu. Gramatycznie to jest niepoprawne i tyle.
Trzeba więc to jakoś obejść…
Wyrażenie to nie funkcja
Dodając do siebie liczby używamy często nawiasów, aby zmienić kolejność działań, np. (2 + 4) * 2
JS traktuje wartość w nawiasach jako wyrażenie. Wykonuje operacje, które są w środku i zwraca wartość (w tym przypadku doda liczby i zwróci 6). Takie wyrażenie może znajdować się w dowolnym miejscu aplikacji. Parser chyba nigdy nie zwróci nam błędu, że nie spodziewa się wyrażenia.
Co jeśli w nawiasie będzie funkcja?
(function() { … }) // lub (() => { … })
Okazuje się, że JS potraktuje tę funkcję jako wyrażenie. Taki zapis jest całkowicie poprawny. Dodajmy teraz do tego kolejny nawias – czyli uruchomienie funkcji.
(function() { ... })()
// lub
(() => { ... })()
Okazuje się, że JS trzyma w pamięci naszą funkcję, ale traktuje ją jak wyrażenie (z racji, że było w nawiasie) a następie dostawia ostatni nawias do wyrażenia – dzięki czemu nasza funkcja się uruchamia!
Podsumowując jest to tak jakby obejście parsera. Dzięki któremu możemy uruchomić antychmiastowo anonimową funkcję, której normalnie byśmy uruchomić nie mogli.
Średniki w JavaScript – wstawiać czy nie?
Temat prawie tak samo drażliwy jak ten czy klamra { za if() powinna być w tej samej czy kolejnej linii.
Średniki w JavaScripcie są opcjonalne, poza paroma sytuacjami, gdzie są obowiązkowe. Brzmi prosto, prawda? W takim raze czy należy ich używać czy nie?
Automatic Semicolon Insertion (ASI)
W JavaScripcie mamy wbudowany pewien mechanizm o nazwie Automatic Semicolon Insertion, który potrafi wstawiać średniki za nas.
Niestety nie jest specjalnie inteligenty, więc to nie jest tak, że o średnikach można zapomnieć. Ale nie ma co panikować, jego zasada działania jest bardzo prosta. ASI przeszukuje kod z lewej do prawej i postępuje wg kilku kroków:
- Jeżeli trafi na coś gramatycznie niepoprawnego (np. const a = 2 const b = 3 – po „2” nie spodziewa się „const”), ale pomiędzy tymi rzeczami jest nowa linia – wstawia średnik
- Jeżeli nie ma nowej linii ale niepasujący znak to „}” – wstawia średnik
- Na końcu pliku – wstawia średnik
- Jeżeli po instrukcjach typu continue, break, throw, return jest nowa linia – wstawia średnik w tej samej linii!!!
- Jeżeli po powyższych instrukcjach jest znak „}” – wstawia przed nim średnik
To znaczy, że jeżeli mamy taki kod:
const a = 2 const b = 4 function test() { return 4 } function test2() { return} function test3() { const a = 2}
Wg wyżej wymienionych zasad zostaną wstawione średniki w ten sposób:
const a = 2;
const b = 4;
function test() {
return;
4;
}
function test2() {
return;}
function test3() {
const a = 2;}
Zagrożenia
Tak jak widaż na przykładzie, mamy pewne zagrożenia widoczne przy słowie „return”. Tak jak jest napisane w pkt. 4 – jeśli po słowie return jest nowa linia, ASI wstawi średni w tej samej. Co prowadzi do tego, że funkcja zwróci „undefined” zamiast naszej wartości! To znaczy, że wartość po tych słowach kluczowych zawsze musi być zwracana w tej samej linii (lub zaczynać się od tej samej linii), np:
return 42
return 'hello'
return {
'name': 'John',
'surname': 'Snow'
}
return [
1, 2, 3, 4, 5
]
Mamy też inne zagrożenia, np. jeśli używamy nawiasów klamrowych [] lub zwykłych (), one mogą być widziane jako składniowo poprawne, np:
const a = 3
[1,2,3].map()
// zostanie odczytane jako
const a=3[1,2,4].map()
const b = 'hello'
(1 + 2).valueOf()
// zostanie odczytane jako
const b = 'hello'(1 + 2).valueOf()
Dlaczego tak się dzieje? Dlatego, że taki zapis jest poprawny. Przecież tak wygląda odwołanie do tablicy, albo wywołanie funkcji. Gramatycznie zapis wygląda jak jedna całość.
Aby się przed tym zabezpieczyć wystarczy przed tymi nawiasami wstawić średnik. Czyli powiedzieć JSowi, że to tutaj zaczyna się nowa instrukcja.
const a = 3
;[1,2,3].map()
I to są najczęstsze problemy, gdy nie stawiamy średników. Na szczęście łatwo im zaradzić.
„To, że czegoś możemy nie robić nie znaczy, że nie powinniśmy”
Taki argument brzmi jakby Automatic Semicolon Insertion (ASI) to była rzecz, którą można wyłączyć. Jakby to był dodatek, którego nie powinniśmy używać.
Nie mniej, należy się pogodzić z myślą, że to coś w JavaScripcie jest i nawet używając średników trzeba to znać i na to uważać. Więc skoro i tak to jest, i tak trzeba to znać, i tak trzeba na to uważać, to dlaczego tego nie używać?
Średniki cię nie uratują
Stawianie średników w każdej linijce zabezpieczy cię maksymalnie przed kilkoma stytuacjami. Czy warto, więc mieć dodatkowy znak przy prawie każdej linijce dla kilku prostych przypadków? Sporo osób powie, że tak. Sporo, że nie.
Wstawiać średniki czy nie?
Gdy wejdzie sie na repozytorium Reacta widzać, że wstawiają. Ale w repo Vue.js już tych średników nie ma.
Decyzja należy do ciebie. Osobiście w większości swoich projektów ich nie wstawiam. Kiedyś wstawiałem, więc można się przestawiać. Dla mnie kod jest czytelniejszy (chociaż, gdy przechodziłem na JSa z PHP miałem odwrotnie wrażenie. Ponieważ tam są średniki. Kwestia przyzwyczajenia.)
Jednocześnie w większości projektach firmowych stawiam średniki. Dlatego, że tak było uzgodnione. Jak zawsze należy się dostosować do teamu i projektu.
Operatory && oraz || (and, or) w JavaScript
Kolejny odcinek, który miał trwać kilka minut a ma ponad 20. Okazuje się, że nawet podstawowe operacje w JavaScripcie mogą być wykorzystane do całkiem zaawansowanych rzeczy.
Dziś o kolejnych dwóch operatorach: && oraz ||.
Czym są operatory logiczne &&, ||
Można powiedzieć, że operator logiczny to funkcja, która przyjmuje 2 wartości i zwraca jeden wynik, zazwyczaj true albo false.
Kilka przykładów:
const a = true && true // zwraca true const b = false && true // zwraca false const c = true && false // zwraca false const d = false && false // zwraca false const a = false || false // zwraca false const b = true || false // zwraca true const c = false || true // zwraca true const d = true || true // zwraca true
Zasada działania jest prosta i logiczna. Gdy mamy operator && (and) spełnione muszą być wszystkie warunki, tzn. wszystkie parametry muszą być prawdziwe. Jeśli chociaż jeden nie będzie spełniony, operator nie sprawdza dalej i zwraca false.
W operatorze || (or), conajmniej jeden parametr musi być prawdziwy. Jeśli taki jest to nie ma sensu sprawdzać drugiego operatora bo wymóg został już spełniony. Tak się właśnie dzieje. Gdy operator trafia na pierwszą prawdziwą wartość, nie sprawdza już dalej bo dostał to czego chciał.
Co przyjmują parametry logiczne?
W poprzednich przykładach używałem wyłącznie parametrów booleanowskich, np. true && true // zwraca true
Ale, operatory te przyjmują KAŻDĄ dowolną wartość. Równie dobrze to może być 23 && 'to jest tekst’ . Pojawia się wtedy pytanie, jak operator rozpoznaje czy wartość jest true czy false, czy spełnia warunek czy nie?
Otóż operator wcale nie sprawdza czy wartość jest true/false. Sprawdza czy wartość jest prawdziwa/fałszywa – uwaga! Słowa klucz!.
Wartości prawdziwe (truthy) i fałszywe (falsy)
Maksymalnie krótko, wartość prawdziwa to taka, która po konwersji na boolean daje true, np.
Boolean(’hello’) => true
Boolean(1) => true
Bollean({}) => true
Natomiast wartość fałszywa to taka, która po konwersji na boolean daje false, np.
Boolean(null) => false
Boolean(0) => false
Żeby było jeszcze łatwiej zapamiętać, wszystkie wartości są prawdziwe, poza tymi pięcioma:
- null
- NaN
- 0
- ” (pusty string)
- undefined
Każda inna po umieszczeniu w Boolean() zwróci true! Proste, prawda?
Czy operatory zawsze zwracają true albo false?
To jest najciekawsze. Te operatory wcale nie zwracają true i false. One zwracają wartości jednego z podanych parametrów! Dokładniej, w przypadku && zwraca wartość ostatniego prawdziwego parametru. Lub pierwszy fałszywy jeśli taki jest.
W przypadku || zwraca pierwszy prawdziwy parametr (stara się wykonać najkrótszą drogę). Jeśli nie ma prawdziwego, zwraca ostatni parametr (ponieważ szukając prawdziwego, przeszedł przez wszystkie i dotarł do ostatniego).
Np. jeśli mamy kod:
3 && 'hello' // 3 jest wartością prawdziwą i 'hello' jest wartością prawdziwą, więc kod zwróci 'hello' 34 && null // 23 jest wartością prawdziwą, 0 jest fałszywą, czyli zwróci null '' && 'word' // pusty string jest wartością fałszywą, zwraca pusty string 'hello' || 'word' // 'hello' jest wartością prawdziwą, zwraca 'hello' null || 34 // null jest wartością fałszywą, zwraca 34
Do czego to się przydaje
Korzystając z tego, że operatory zwracają jedną z podanych wartości, można to wykorzystać do szybkiego tworzenia zmiennych, bez dodatkowych instrukcji warunkowych.
Np. jeśli chcę stworzyć zmiennną, która przyjmuje wartość od innej zmiennej „userMoney”, lub nadać jej domyślną wartość = 18, mogę zrobić coś takiego:
const money = userMoney || 100
jeśli wartość z „userMoney” będzie wartością prawdziwą to operator || zwróci wartość z „userMoney”. Jeśli natomiast będzie fałszyła, operator zwróci pierwszą wartość prawdziwą czyli 100.
Inny przykład. Który ma bardzo częste zastosowanie w prawdziwym kodzie: mamy obiekt „cat” a w nim wartość „name”, do której chcemy się później odwołać.
const cat = { name: 'Flerkin'} const catsName = cat.name
Ale co jeśli okaże się, że obiekt „cat” będzie pusty? Odwołanie do cat.name zwróci błąd.
const cat = null const catsName = cat.name // błąd: Cannot read property 'name' of null
Możemy się przed tym łatwo zabezpieczyć.
const cat = null const catsName = cat && cat.name // zwraca 'null' ale nie błąd
Możemy jeszcze dopisać, że jeśli pobranie nazwy obiektu „cat” się nie uda to nadaj mu wartość domyślną, np. „Mruczek”
const cat = null const catsName = cat && cat.name || "Mruczek"
Tak jak widać, proste operatory a możemy użyć je w już niekoniecznie prosty sposób. Zachęcam do obejrzenia wideo z początku wpisu, tam staram się to dokładniej opisać:)
== vs ===, czyli o koercji typów w JavaScript
Pierwszy odcinek z serii zrozumieć JavaScript będzie o operatorach? Tak, głównie o tym pierwszym, czyli podwójnym.
Nie jest to odcinek stricte o koercji typów, bo omawiam je na konkretnym przykładzie, na przykładnie operatora „==”. Ale to wystarczy żeby załapać zasadę działania tego mechanizmu.
Chciałem, żeby ten odcinek miał max. 10 minut… wyszło ponad 20 a wydaje mi się, że mówiłem zwięźle. Myślę, że to najlepszy dowód, że zwykłe porównanie operatorów wcale nie jest takie proste!
== vs ===
Mówiąc prostym językiem jaka jest różnica pomiędzy tymi operatorami? Ten potrójny jest dokładniejszy. Natomiast ten podwójny jest mniej dokładny.
Potrójny operator porównania … === …
Teraz trochę dokładniej. Potrójny operator sprawdza czy wartości po obu stronach są IDENTYCZNE!
Identyczne to znaczy czy ich wartość się zgadza, np. czy to jest 5, czy 4, czy ’hello’, oraz czy zgadza się ich typ, czyli czy jest to tekst, liczba czy boolean.
'2' === 2 // false
2 === 2 // true
Pierwszy przykład zwróci false, ponieważ ’2′ jest stringiem, czyli tekstem bo jest w cudzysłowie. Natomiast drugi parametr 2 jest typu number, czyli jest liczbą. Wynika z tego, że oba parametry nie są IDENTYCZNE. W drugim oba parametry mają taką samą wartość (2) oraz są tego samego typu (number), mówiąc prościej – są identyczne.
Podwójny operator porównania … == …
Tutaj zaczyna się dziać trochę magii. W podwójnym operatorze porównania JS zaczyna trochę myśleć „samodzielnie”. Próbuje pomóc i w kilku krokach zmienia typy parametrów na takie, aby na końcu zwrócić true (o ile się da).
Np. jeżeli mamy '2′ == 2 to JS zmieni typ pierwszego parametru na number. Sam możesz to zrobić w konsoli przeglądarki, wpisz Number(’2′). Wtedy kolejny krok wygląda już tak 2 == 2. Jeśli parametry są tego samego typu (oba są typu number) to następuje kolejny krok, czyli porównania potrójne 2 === 2, a to wiemy już, że zwróci true, prawda?
Koercja typów
Nie działa jednak kompletnie chaotycznie, chociaż na pierwszy rzut oka może się tak wydawać. Proces zmiany typu parametru nazywany jest koercją typów. Trudne słowo, które ma proste znaczenie: zmiana typu wartości na inny typ.
W podwójnym operatorze zmiana tych typów następuje wg ściśle określonych 10 króków:
- Jeśli oba parametry są tego samego typu porównaj je jeszcze raz potrójnym operatorem … === …
- Jeśli pierwszy jest null a drugi undefined, zwróć true. To trzeba zapamiętać.
- Odwrotność drugiego. Pierwszy to undefined, drugi null. Jak można się domyśleć, także zwróci true.
- Jeśli pierwszy jest number a drugi string. Stara się zmienić tekst na liczbę (w poprzednim akapicie wspomniałem jak można to zrobić). Następnie powtarza wszystkie kroki od początku.
- Odwrotność czwartego. Czyli pierwszy to string a drugi number. Zmienia typ stringu na number i powtarza wszystkie kroki.
- Jeśli pierwszy jest boolen a drugi czymkolwiek. Stara się zmienić boolean na number i powtarza wszystkie kroki (Number(true) = 1, Number(false) = 0).
- Odwrotność szóstego.
- Jeśli pierwszy jest wartością prymitywną (string, number, symbol) a drugi obiektem. Stara się zmienic obiekt to wartości prymitywnej i powtarza wszystkie kroki. Jak zmenić
- Odwrotność ósmego.
- Jeżeli żaden z poprzednich punktów nie jest naszym przypadkiem, zwóć false.
Powyższe 10 kroków to jedna iteracja, czyli jedno powtórzenie. Tych powtórzeń będzie tyle, aż w końcu dostaniemy true albo false. Ot, cała magia.
Kilka przykładów:
'2' == 2 // krok 5, ponieważ pierwszy parametr to string, drugi to number
2 == 2 // krok 1, poniważ oba parametry są tego samego typu (number)
2 === 2 // zwraca true, koniec koercji
null == undefinied // krok 2, zwróci true, koniec porównania
[] == 0 // krok 9, ponieważ pierwszy parametr to obiekt, następuje zmiana tablicy w wartość prymitywną (w tym przypadku w pusty string)
'' == 0 // krok 5, ponieważ pierwsza wartosć to string, druga to number, następuje zmiana stringu na number
0 == 0 // krok 1, ponieważ oba parametry są już tego samego typu
0 === 0 // zwraca true, koniec koercji
Po więcej przykładów i dokładniejsze wytłumaczenie zapraszam do filmu:)
Nowa seria „Zrozumieć JavaScript”
Dziś rusza kolejna mała seria na YouTubie, tym razem o JavaScripcie!
Tak, odcinków o JavaScripcie jest już sporo… Mam jednak wrażenie, że większość podchodzi do tematu w stylu „zrób to, a stanie się tak”. Ja natomiast chcę podejść do tematu od innej strony, czyli pokazać dlaczego dzieje się tak a nie inaczej. Poznać ten dziwny język bardziej od środka i zwyczajnie go zrozumieć.
Inny przykład? Ile frameworków znasz? Pewnie kilka, a czy potrafisz wyjaśnić jak one działają, dlaczego zachowują się tak a nie inaczej?
To nie jest seria „jak nauczyć się JavaScriptu”, wymagana jest jednak jakaś podstawowa wiedza. Chociaż początkujący też mogą śmiało ją oglądać. Chcę pokazać co się dzieje pod maską JSa.
O serii wpominałem na moim newsletterze, do którego serdecznie zapraszam, podobno warto 🙂 https://tworcastron.pl/zapis.html
Pierwszy rzeczowy odcinek już jutro!
MongoDB + Node.js – kurs w 60 minut
Jakiś czas temu przygotowałem 2 odcinki o Node.js oraz bazach danych.
Node.js – kurs w 60 minut
SQL vs noSQL | MySQL vs MongoDB – różnice
Dziś naturalna kontynuacja tematu, czyli odcinek poświęcony nierelacyjnej bazie danych MongoDB.
MongoDB
Nie będę się powtarzał i wymieniał wady i zalety MongoDB, robiłem to już w ww. odcinku. Dla przypomnienia, jego najbardziej charakterystyczne cechy to:
- szybkość
- skalowalność
- brak Schema (brak ściśle zdefiniowanej struktury danych)
- brak relacyjności
Node.js
Na temat Noda też nie poświęcam za dużo czasu. Odsyłam od odcinku wpomnianego wyżej.
MongoDB + Node.js
Łącząc oba narzędzia w jednym odcinku znajdziecie informacje takie jak:
- instalacja bazy danych, uruchomienie
- połącznie MongoDB z Node.js
- podstawy pracą z bazą (tworzenie bazy, kolekcji)
- pobieranie, dodawanie, usuwanie danych
- czym dokładnie jest ObjectID – czyli domyślne pole ID w MongoDB
- Robo3T – czyli graficzny interfejs do MongoDB
- Mongoose – usprawnienie pracy z bazą danych
- Schema!
- Validacja i sanityzacja danych
SQL vs noSQL | MySQL vs MongoDB – różnice
Niedawno w jednym z odcinków na YT na temat Node.js wspomniałem o tym, że popularnym wyborem dla noda jest mongoDB.
Nie wspomniałem, że mongoDB jest bazą nierelacyjną w przeciwieństwie do poczciwego MySQL, który jest bazą relacyjną.
Prawdopodobnie nie każdy zdaje sobie sprawę co to właściwie oznacza. Czy to tylko 2 wersje tego samego? Absolutnie nie! Różnice są dosyć spore i dzisiaj właśnie o nich.
Poniżej film oraz jeszcze niżej – tekst dla osób preferujących czytanie
— SQL (RDBMS)
Baza typu SQL tak naprawdę nazywa się bazą typu RDBMS (RElational Database Management System), czyli system zarządzania relacyjną bazą danych. Nazwa SQL jest tak naprawdę uproszczeniem, ponieważ bazy tego typu korzystają z języka SQL (Structured Query Language), czyli strukturyzowanego języka zapytań.
Najpopularniejszym przedstawicielem tej bazy jest poczciwy MySQL (powstały w 1995), od którego większość z nas zaczynała naukę baz.
Struktura
Struktura jest dosyć prosta, główny obiekt to nasza baza danych. Następnie w bazie mamy tabele. Tak jak w zwykłej tabeli, mamy kolumny a w nich wiersze/rekordy. Kolumny opisują jakie dane się w nich znajdują oraz ile ich jest. Każdy wiersz wygląda więc tak samo,i chodzi o jego strukturę.
Cechy
- oczywiście bazy relacyjne posiadają RELACJE, czyli połączenia pomiędzy tabelami (gdybyśmy mieli tabele users i orders, to w zamówieniu umieszczamy jedynie ID użytkownika – tworzymy relacje, zamiast kopiować dane)
- kolejną główną cechą jest użycie języka SQL, w którym piszemy zapytania. Jeśli widziałeś kiedyś kod typu „SELECT id, name FROM users” – to jest właśnie SQL
- dzięki SQLowi możemy tworzyć długie i skomplikowane zapytania, dopiero gotowe zapytanie wysyłane jest do bazy danych i przetwarzane
- Schema – tabele w bazach relacyjnych zawierają KOLUMNY, które to opisują jak wyglądają dane w tej tabeli, to jest właśnie tak zwany Schema, czyli schemat tabeli. Dzięki temu wszystkie wiersze w tabeli są takie same.
- skalowalność wertykalna – oznacza to, że jeśli chcemy wzmocnić naszą bazę musimy wzmocnić jej pojedynczy serwer, dodając np. RAM, mocy procesora lub zwiększając pojemność dysku. Nie możemy dołączyć kolejnego serwera.
— NoSQL
Baza nierelacyjna nazywana jest noSQL, ponieważ nie używa wspomnianego wcześniej języka SQL. Zamiast tego używa JavaScriptu. Powoduje to kilka różnic w samym działaniu takiej bazy, o czym za chwilę.
Struktura
Tak samo, jak przy poprzedniej bazie, podstawowym elementem jest baza danych. Baza danych zawiera tabele, chciałem napisać kolekcje. Chociaż pełnią tę samą rolę. Główna różnica to nazewnictwo, wynikające w kolejnego punktu. Kolekcje zawierają dokumenty.
W przeciwieństwie do baz relacyjnych, kolekcje nie mają ściśle określonej struktury, dlatego wiersze, tzn. dokumenty mogą wyglądać różnie, mimo że są w tej samej tabeli kolekcji. Dzieje się tak dlatego, że wiersze dokumenty są dokumentem w formacie JSON, a nie wierszem w tabeli.
* powyższe przekreślone pomyłki wykonane są specjalnie, aby lepiej zobrazować czym są kolekcje i dokumenty w porównaniu do tabel i wierszy
Cechy
- ponieważ nie używa SQLa, zapytania tworzymy w języku JavaScript, jeśli to jest nasze środowisko (lub innym, jeśli pracujemy w innym. MongoDB udostępnia drivery dla wielu języków, co oznacza, że możesz tworzyć zapytania w swoim języku)
- jak mówi sama nazwa, taka baza nie ma relacji – oznacza to, że kolekcje nie są ze sobą w żaden sposób połączone. Może to powodować duplikowanie danych.
- brak Schema (lub dynamiczny Schema) – kolekcje nie mają „kolumn”, czyli nie mają określonej struktury, dlatego dokumenty mogą się różnić, mimo że są w tej samej kolekcji
- skalowalność horyzontalna i wertykalna
- szybkość działania – mongoDB jest znacznie szybsza niż mySQL, szczególnie widoczne przy big data
Co jest lepsze?
Jak zawsze odpowiedź na to pytanie jest jedna: to zależy.
Baza nierelacyjna noSQL działa szybciej oraz jest skalowalna horyzontalnie co pozwala na pracę z big data.
Baza relacyjna (SQL) zapewnia większą integralność danych (dzięki Schema) oraz relacje.
W zależności od projektu możesz potrzebować innych cech.