8. MongoDB baza podataka
Cilj ovog poglavlja je upoznavanje studenata sa kreiranjem serverskih aplikacija koji komuniciraju sa MongoDB bazom podataka. Nakon ovog poglavlja, student bi trebalo da razume način funkcionisanja MongoDB baze podataka, kao i da samostalno kreira modele podataka, i da upravlja njima kroz četiri osnovne operacije: pravljenje novih podataka, kao i čitanje, menjanje i brisanje postojećih podataka (engl. Create, Read, Update, Delete, skr. CRUD).
8.1 MongoDB
Baza podataka (engl. database) predstavlja sistem koji se sastoji od struktura podataka i algoritama čija je uloga trajno skladištenje podataka. Pod trajnim skladištenjem smatramo činjenicu da, jednom kada se podaci sačuvaju u bazu podataka, oni ostaju zapamćeni u njoj, čak i kada se aplikacija koja je te podatke upisala u bazu podataka završi. To znači da uvek kada želimo da naše podatke imamo zabeležene nezavisno od životnog veka aplikacije, neophodno nam je da te podatke čuvamo u bazama podataka. Takođe ćemo koristiti i termin sistem za upravljanje bazom podataka, skr. SUBP (engl. database management system, skr. DBMS) koji predstavlja softver koji se koristi za upravljanje bazama podataka. Ti softveri se koriste za kreiranje novih i izmenu postojećih baza podataka, čuvanje podataka i dr.
MongoDB pripada grupi tzv. nerelacionih (engl. NoSQL) SUBP, odnosno, same baze podataka koje se kreiraju su nerelacione. Postoji više vrsta nerelacionih baza podataka, a baze podataka u MongoDB SUBP pripadaju vrsti koja se naziva baza dokumenata (engl. document database). To znači da se svi podaci čuvaju u obliku dokumenata. Format u kojem su zapisani ovi dokumenti je sličan formatu JSON objekata. Vrednosti svojstava (nekada kažemo i polja (engl. field)) dokumenta mogu biti: niske, brojevi, drugi dokumenti, nizovi, nizovi drugih dokumenata, itd. Naredna slika ilustruje primer dokumenta koje je sačuvan u nekoj bazi podataka u MongoDB SUBP.
Bazu podataka u MongoDB SUBP čine kolekcije (engl. collection) dokumenata. Svaki dokument može biti različit, sa proizvoljenim brojem polja, veličine i sadržaja.
Sledeći pojmovi su bitni za razumevanje MongoDB SUBP:
-
_id
- Ovo je polje obavezno za svaki dokument u MongoDB bazi. Predstavlja jedinstvenu vrednost po kojoj razlikujemo dokumente u bazi. Pošto je polje obavezno, ukoliko pokušamo da napravimo novi dokument bez njega, biće automatski dodato. -
Kolekcija
- Predstavlja grupisane dokumente. Kolekcija postoji unutar jedne baze. Kao što smo već napomenuli, kolekcije nemaju definisanu strukturu, svaki dokument može biti različit. -
Kursor
- Pokazivač na rezultujući skup našeg upita. Klijenti mogu iterirati kroz ovaj skup kako bi dobili rezultate. -
Baza podataka
- Skladište za kolekcije. Svaka baza ima svoj skup datoteka. -
Dokument
- Jedan zapis u kolekciji. Sastoji se od naziva polja i vrednosti. -
Polje
- Par (ime, vrednost) jednog dokumenta. Dokument može imati 0 ili više polja. -
JSON
- Notacija za predstavljanje strukturiranih podataka u čitljivom formatu.
8.2 Instalacija
Kako bi rad sa MongoDB SUBP bio moguć potrebno je preuzeti instalaciju. Odabrati verziju 4.2.2, odgovarajući operativni sistem i paket. Detaljna uputstva za instalaciju možete pogledati ovde.
8.3 MongoDB shell
Korišćenjem MongoDB shell programa možemo se povezati sa bazom i izvršavati različite upite nad kolekcijama koje sadrži. Potrebno je pokrenuti shell skript koji dolazi uz mongo
server (<instalacioni_direktorijum>/Server/4.2/bin/mongo
).
U nastavku dajemo odabrane naredbe koje je moguće izvršiti u MongoDB shell programu za upravljanje bazama podataka:
-
show dbs
- Izlistava nazive svih baza na serveru. -
use <db>
- Pristupa bazi sa nazivom koji se zadaje. Svi upiti se vrše nad odabranom bazom sve dok se ova naredba ne ponovi sa nazivom druge baze. -
show tables
- Izlistava sve kolekcije iz odabrane baze. -
db.<collection>.find()
- Izlistava sve dokumente iz zadate kolekcije. -
db.<collection>.find(<upit>)
- Izlistava sve dokumente iz zadate kolekcije koji ispunjavaju uslove zadate upitom. -
db.<collection>.find(<upit>, <projekcija>)
- Izlistava sve dokumente iz zadate kolekcije koji ispunjavaju uslove zadate upitom, pri čemu se vrši i projekcija rezultata. -
db.<collection>.insert(<dokument>)
- Dodaje jedan nov dokument u zadatu kolekciju. -
db.<collection>.insert([<dokument1>, <dokument2>, ...])
- Dodaje više novih dokumenata u zadatu kolekciju. -
db.<collection>.insertOne(<dokument>)
- Dodaje jedan nov dokument u zadatu kolekciju. -
db.<collection>.insertMany([<dokument1>, <dokument2>, ...])
- Dodaje više novih dokumenata u zadatu kolekciju. -
db.<collection>.update(<upit>, <objekat sa izmenama>)
- Menja polja jednog dokumenta koji ispunjava uslove zadatog upita. -
db.<collection>.updateMany(<upit>, <objekat sa izmenama>)
- Menja polja svih dokumenata koji ispunjavu uslove zadatog upita. -
db.<collection>.deleteOne(<upit>)
- Briše jedan dokument koji ispunjava uslove zadatog upita. -
db.<collection>.deleteMany(<upit>)
- Briše sve dokumente koji ispunjavu uslove zadatog upita. -
db.<collection>.drop()
- Uništava kolekciju i sve dokumente koji se nalaze u njoj. -
db.dropDatabase()
- Uništava trenutno aktivnu bazu podataka i sve kolekcije, odnosno, dokumenta koji se nalaze u njoj.
MongoDB shell program ne sadrži operaciju za kreiranje nove baze podataka. Umesto toga, baza se automatski kreira kada se u nju trajno zapiše prvi dokument. Tako, na primer, ukoliko MongoDB SUBP nije imao bazu podataka myNewDB
, nakon izvršavanja naredne dve naredbe, biće kreirana nova baza podataka myNewDB
koja će sadržati jednu kolekciju myNewCollection1
koja će sadržati jedan dokument:
> use myNewDB
> db.myNewCollection1.insertOne( { x: 1 } )
Takođe, vredno je napomenuti da su opisane naredbe primenljive samo u MongoDB shell programu, a ne u drugim radnim okvirima, drajverima i sl. U poglavlju u kojem budemo govorili o Mongoose.js radnom okviru, primetićemo da postoji veliki broj metoda čiji nazivi odgovaraju prethodno opisanim naredbama. Međutim, ne treba ih mešati sa naredbama iznad, već one imaju drugačiju semantiku!
8.4 Upiti
Pre nego što se upustimo u ovu oblast potrebno je da pripremimo podatke za obradu. U datoteci koju možete preuzeti sa ove veze nalaze se podaci o pojedinačnim studentima. Podaci su zadati u JSON
formatu i kao takvi se lako mogu uvesti u MongoDB
bazu programom mongoimport
1:
mongoimport --db <db_name> --collection <collection_name> --file <path>
gde se umesto <db_name>
navodi ime baze u koju se uvoze podaci, zatim naziv kolekcije u koju se podaci uvoze umesto <collection_name>
i putanju do datoteke koja sadrži podatke umesto <path>
.
Zadatak 0. U kolekciju
students
iz bazeFakultet
uvesti podatke o studentima iz datoteke studenti.json.
mongoimport --db Fakultet --collection students --file studenti.json
U nastavku podrazumevamo da smo otvorili MongoDB shell program (mongo
) i da smo postavili da radimo sa prethodno uvezenom bazom podataka Fakultet
na sledeći način:
> use Fakultet
8.4.1 Upiti čitanja
Da bismo dohvatili podatke iz baze moramo napisati upit (engl. query) koji specifikuje ograničenja koja dokumenti moraju da ispunjavaju da bi bili dohvaćeni. Upiti u MongoDB SUBP predstavljaju objekte čija su svojstva tipovi ograničenja, a vrednosti tih svojstava su vrednosti odgovarajućih ograničenja:
{
<ogranicenje1>: <vrednost1>,
<ogranicenje2>: <vrednost2>,
...
}
Specijalno, ako bismo želeli da dohvatimo podatke o svim studentima u kolekciji, koristili bismo prazan upit, odnosno
{}
Zadatak 1. Iz kolekcije
students
izdvojiti sve studente koji se zovuJovana
.
> db.students.find({name: "Jovana"})
Ukoliko je navedeno više od jednog svojstva, traže se svi dokumenti koji za svako od navedenih naziva polja imaju navedenu vrednost. Ako se bar jedno polje ne poklapa po vrednosti sa zadatom, on neće biti prikazan kao rezultat.
Zadatak 2. Iz kolekcije
students
izdvojiti sve studente koji se zovuJovana
i čiji je prosek jednak8.5
.
> db.students.find({
name: "Jovana",
avg_grade: "8.5"
})
Na ovaj način dobijamo poređenje vrednosti po jednakosti. Nekada će nam biti potrebno da pronađemo dokumente sa vrednostima koje su manje ili veće od zadate, koje su u nekom intervalu, itd. Definisana su posebna svojstva koja možemo pisati u upitu koja predstavljaju ova ograničenja:
$gt
- pronalazi vrednosti veće od zadate$gte
- pronalazi vrednosti veće ili jednake zadatoj$lt
- pronalazi vrednosti majne od zadate$lte
- pronalazi vrednosti manje ili jednake zadatoj$ne
- pronalazi vrednosti koje nisu jednake zadatoj$eq
- pronalazi vrednosti jednake zadatoj$in
- pronalazi vrednosti jednake nekoj iz zadatog niza vrednosti$nin
- pronalazi vrednosti nisu jednake nijednoj iz zadatog niza vrednosti.
Sintaksa za ove operatore je sledeća:
{
<polje>: {
$<operator>: <vrednost>
}
}
Dakle, za polje čije je ime zadato umesto vrednosti navodimo objekat koji sadrži operator kao svojstvo, a vrednost koja se zadaje predstavlja broj ili niz brojeva sa kojima se poredi vrednost zadatog polja.
Zadatak 3. Iz kolekcije
students
izdvojiti sve studente sa prosekom većim od8.5
.
> db.students.find({
avg_grade: {
$gt : "8.5"
}
})
Zadatak 4. Iz kolekcije
students
izdvojiti studente sa prosekom između 8.0 i 9.0.
> db.students.find({
avg_grade: {
$gte : "8.0",
$lte : "9.0"
}
})
Zadatak 5. Iz kolekcije
students
izdvojiti studente smerovaInformatika
iRacunarstvo i informatika
.
> db.students.find({
major: {
$in : ['Informatika', 'Racunarstvo i informatika']
}
})
Pored toga, možemo koristiti i svojstva koja imaju ulogu logičkih operatora:
$and
- pronalazi sve dokumente koji su ispunili uslove oba upita$or
- pronalazi sve dokumente koji su ispunili uslove bar jedan od upita$not
- pronalazi sve dokumente koji nisu ispunili uslove upita$nor
- pronalazi sve dokumente koji nisu ispunili uslove nijednog upita
Vrednosti ovih svojstava su nizovi objekata koji predstavljaju logičke jedinice i povezuju se odgovarajućim logičkim operatorom. U slučaju operatora konjunkcije, ukoliko se u nizu nalaze jednostavni objekti, koji su ranije opisani, možemo izostaviti operator i samo razdvajati zarezom sve objekte. Međutim, ukoliko imamo uslove koji su nešto kompleksniji, npr. uslovi koji sadrži i neke druge logičke operatore, onda moramo koristiti $and
eksplicitno.
Korišćenje logičkih operatora može se predstaviti sledećim objektom:
{
$<operator>: [
{ <polje1>: <vrednost1> },
{ <polje2>: <vrednost2> },
...
]
}
Zadatak 6. Iz kolekcije
students
izdvojiti sve studente čiji je prosek veći od8.0
sa smeraInformatika
.
> db.students.find({
$and: [
{ avg_grade: { $gt: 8.0 } },
{ major: `Informatika` }
]
})
Prethodni upit predstavlja konjunkciju, i on se može jednostavnije zapisati navođenjem zapete između uslova poređenja, tj.:
> db.students.find({
avg_grade: { $gt: 8.0 },
major: `Informatika`
})
Zadatak 7. Iz kolekcije
students
izdvojiti informacije o studentima čiji je prosek jednak9.0
ili10.0
i koji su upisali smerInformatika
iliStatistika
.
> db.students.find({
$and: [
{
$or: [ { avg_grade: 9.0 }, { avg_grade: 10.0 } ]
},
{
$or: [ { major: 'Informatika' }, { major: 'Statistika' } ]
}
]
})
U prethodnim upitima vrednosti polja su poređenje niskama onakve kakve su zadate. Nekada je potrebno proveriti da li vrednost polja počinje ili završava nekom niskom, ili da li sadrži neku nisku.
-
Ukoliko želimo da vrednost nekog polja počinje nekom niskom, onda tu nisku navodimo između
/^
i/
. -
Ukoliko želimo da vrednost nekog polja završava nekom niskom, onda tu nisku navodimo između
/
i$/
. -
Ukoliko želimo da vrednost nekog polja sadrži neku nisku, onda tu nisku navodimo između
/
i/
.
Zadatak 8. Iz kolekcije
students
izdvojiti informacije o studentima čije prezime počinje karakteromP
.
> db.students.find({
surname: /^P/
})
8.4.2 Projekcija u upitima za čitanje vrednosti
Ukoliko ne želimo da u rezultatu dobijemo sva polja za dokumente, možemo iskoristiti projekciju (engl. projection) rezultata. Projekcija predstavlja objekat čija je sintaksa oblika:
{
<polje1>: <vrednost1>,
<polje2>: <vrednost2>,
...
}
Polja u projekciji predstavljaju polja koja se nalaze u dokumentu, a vrednosti u projekciji mogu biti:
0
ilifalse
: polje neće biti obuhvaćeno u rezultatu1
ilitrue
: polje će biti obuhvaćeno u rezultatu
Podrazumevano, ukoliko ne navedemo projekciju, sva polja iz dokumenta će biti dohvaćena. Ukoliko ipak navedemo projekciju, tada će biti dohvaćena samo ona polja koja su eksplicitno navedena da budu uključena (vrednost 1
ili true
u projekciji), dok će ostala polja biti isključena iz rezultata. Specijalno, polje _id
će se uvek naći u rezultatu, osim ako eksplicitno ne navedemo _id: 0
(ili id_: false
) u objektu projekcije.
Zadatak 9: Iz kolekcije
students
izdvojiti informacije o imenu, prezimenu i prosečnoj oceni onih studenata čije prezime počinje karakteromP
.
> db.students.find(
// Upit
{
surname: /^P/
}
// Projekcija
{
_id: 0,
name: 1,
surname: true,
avg_ocena: 1
}
)
8.4.3 Upiti za ažuriranje vrednosti polja
Ukoliko bismo želeli da izmenimo neku vrednost upisanu u bazu možemo koristiti neki od sledećih operatora:
$currentDate
- Postavlja vrednost polja na trenutni datum. Vrednost ovog svojstva je objekat koji sadrži jedno ili više polja čije se vrednosti menjaju. Za svako polje se kao vrednost može navesti:-
bulova vrednost
true
čime se naznačava da se vrednost zadaje uDate
formatu, -
objekat, koji određuje tip (svojstvo
$type
) polja i može bititimestamp
ilidate
, u notaciji{ $type : 'timestamp' }
ili
{ $type : 'date' }
-
-
$inc
- Uvećava trenutnu vrednost jednog ili više polja za zadate vrednosti. -
$mul
- Množi trenutnu vrednost jednog ili više polja za zadate vrednosti. $set
- Postavlja vrednost jednog ili više polja na zadate vrednosti.
Sintaksa ovih svojstava je sledeća:
{
$<svojstvo>: {
<polje1>: <vrednost1>,
...
}
}
gde se redom navode imena polja čije se vrednosti menjaju na prethodno opisan način i nove vrednosti za ta polja.
Za više informacija o operatorima ažuriranja možete pogledati ovde.
Zadatak 10. U kolekciji
students
izmeniti napomenu uIzvanredni studenti informatike
svim studentima smeraInformatika
iliRacunarstvo i informatika
čiji je prosek veći od9.5
, a zatim izlistati sav sadržaj kolekcije.
> db.students.updateMany(
// Prvo navodimo upit koja dokumenta azuriramo
{
$and: [
{ $or: [{major: 'Informatika'}, { major: 'Racunarstvo i informatika'}] },
{ avg_grade: {$gt: 9.5} }
]
},
// A zatim navodimo upit na koji nacin ta dokumenta azuriramo
{
$set: {
note: "Izvanredni studenti informatike"
}
}
)
> db.students.find()
- U kolekciju `artikli` uvesti podatke o artiklima iz datoteke artikli.json.
- U kolekciju `produzbine` uvesti podatke o porudžbinama iz datoteke porudzbine.json.
-
Program
mongoimport
nalazi se u istom direktorijumu gde imongo
. ↩