This shows you the differences between two versions of the page.
bd2:laboratoare:11 [2019/12/06 17:50] ciprian.truica [Funcții] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratorul 11 - MongoDB ====== | ||
- | ===== Obiective ===== | ||
- | |||
- | * Comenzi MongoDB | ||
- | * Operații DML | ||
- | * Indexare | ||
- | * Funcții | ||
- | * Agregarea datelor | ||
- | |||
- | |||
- | ===== Comenzi MongoDB ===== | ||
- | |||
- | ==== Pornire MongoDB ==== | ||
- | |||
- | Pentru a porni baza de date MongoDB se va folosi demonul **mongod**([[https://docs.mongodb.com/manual/reference/program/mongod/|mongod]]). | ||
- | |||
- | Procesul demon **mongod** poate porni cu următorii paramterii: | ||
- | |||
- | * **''-''''-''config <filename>** specifică un fisier de configurare | ||
- | * **''-''''-''port <port>** pentru a specifica portul pe care asculta procesul demon, implicit 27017 | ||
- | * **''-''''-''bind_ip <hostnames|ipaddresses|Unix domain socket paths>** pentru a specifica addresa de | ||
- | * **''-''''-''dbpath <path>** calea către directorul unde se vor stoca fișierele de stocare. | ||
- | |||
- | Exemplu utilizare **mongodb** | ||
- | |||
- | <code bash> | ||
- | mongod --port 27018 --bind_ip 192.100.10.10 --dbpath /data | ||
- | </code> | ||
- | |||
- | <color red>Ex. 1.</color> Să creeze un director pe discul ''Student'' numit ''mongo_data''. Să se pornească baza de date cu folosind ca director de stocare noul director creat. Restul valorilor rămân cele implicite. | ||
- | |||
- | ==== Conectare MongoDB ==== | ||
- | |||
- | Pentru a va conecta la un server MongoDB, se folosește interpretorul în linie de comandă **mongo** ([[https://docs.mongodb.com/manual/mongo/|Documentație]]). | ||
- | |||
- | Exemplu de utilizare: | ||
- | |||
- | <code bash> | ||
- | # se conectează implicit la localhost pe portul 27017 | ||
- | mongo | ||
- | |||
- | # se conectează la hostname folosind portul implicit 217017 | ||
- | mongo --host hostname | ||
- | |||
- | # se conectează implicit la localhost folosind portul port | ||
- | mongo --port 27017 | ||
- | |||
- | # se conectează la hostname folosind portul port | ||
- | mongo --host hostname:27017 | ||
- | |||
- | mongo --host hostname --port 27017 | ||
- | |||
- | </code> | ||
- | |||
- | <color red>Ex. 2.</color> Conectați-vă la MongoDB. | ||
- | |||
- | ==== Comenzi CLI MongoDB ==== | ||
- | |||
- | Pentru a vedea baza de date curentă se folosește comanda **db**. | ||
- | |||
- | Pentru a vedea toate bazele de date existente se folosește comanda **show dbs**. | ||
- | |||
- | Pentru a vă conecta la o baza de date sau a crea o nouă bază de date se folosește comanda **use DATABASE_NAME**. În cazul în care se folosește comanda **use** pentru a crea o bază de date, aceasta va deveni persistentă numai dacă se crează o colecție sau se inserează o înregistrare. | ||
- | |||
- | Pentru a vedea toate colecțiile se folosește comanda **show collections**. | ||
- | |||
- | Puteți folosi una din următoarele metode pentru a crea o nouă colecție: | ||
- | * **db.createCollection("COLLECTION_NAME")**, unde **COLLECTION_NAME** este numele noii colecții | ||
- | * inserați o înregistrare și colecția se va crea automat. | ||
- | |||
- | Pentru a șterge o colecție se folosește comanda **db.COLLECTION_NAME.drop()**. | ||
- | |||
- | Pentru a șterge o baza de date se folosește comanda **db.dropDatabase()**. Trebuie să fiți conectați la baza de date (folosing **use**) pentru a o șterge. | ||
- | |||
- | <note important>Numele bazelor de date este case sensitive.</note> | ||
- | |||
- | <color red>Ex. 3.</color> Creați o bază de date numită **faculty** care să conțină colecția **students**. | ||
- | |||
- | |||
- | ===== Operații DML ===== | ||
- | |||
- | ==== Inserarea datelor ==== | ||
- | |||
- | Pentru a adăuga date în MongoDB puteți sa folosiți una din metodele: | ||
- | |||
- | * Insert sau Bulk Insert ([[https://docs.mongodb.com/manual/reference/method/db.collection.insert/|Documentație]]) | ||
- | * **mongoimport** ([[https://docs.mongodb.com/manual/reference/program/mongoimport/|Documentație]]) | ||
- | |||
- | === insert() === | ||
- | |||
- | Comanda Insert are următoare sintaxa | ||
- | |||
- | <code javascript> | ||
- | db.collection.insert( | ||
- | <document or array of documents>, | ||
- | { | ||
- | writeConcern: <document>, | ||
- | ordered: <boolean> | ||
- | } | ||
- | ) | ||
- | </code> | ||
- | |||
- | Un document dintr-o colecție este în format BSON: | ||
- | |||
- | <code javascript> | ||
- | { | ||
- | "student": | ||
- | { | ||
- | "firstname": "Ion", | ||
- | "lastname": "Popescu" | ||
- | }, | ||
- | "an": 4, | ||
- | "grupa": "342C3", | ||
- | "materii": | ||
- | [ | ||
- | {"nume": "BD2", "an": 4}, | ||
- | {"nume": "Comp", "an": 4}, | ||
- | {"nume": "SO2", "an": 4} | ||
- | ], | ||
- | "cunostinte": ["SQL", "Java", "PL/SQL"] | ||
- | } | ||
- | |||
- | </code> | ||
- | |||
- | Pentru a insera documentul în colecția students: | ||
- | |||
- | <code javascript> | ||
- | db.students.insert( | ||
- | { | ||
- | "student": | ||
- | { | ||
- | "firstname": "Ion", | ||
- | "lastname": "Popescu" | ||
- | }, | ||
- | "an": 4, | ||
- | "grupa": "342C3", | ||
- | "materii": | ||
- | [ | ||
- | {"nume": "Comp", "an": 4}, | ||
- | {"nume": "BD2" , "an": 4}, | ||
- | {"nume": "SO2" , "an": 4} | ||
- | ], | ||
- | "cunostinte": ["SQL", "Java", "PL/SQL"] | ||
- | } | ||
- | ) | ||
- | </code> | ||
- | |||
- | Pentru a va ușura munca puteți sa va creați variabile la nivelul consolei. Dacă se dorește inserarea mai multor înregistrari, se poate declara un vector. | ||
- | |||
- | <code javascript> | ||
- | var stud = {"student": { "firstname": "Andrei", "lastname": "Ionescu"}, "an": 4, "grupa": "341C4", "materii": [{"nume": "BD2", "an": 4}, {"nume": "IA", "an": 4},{"nume": "IAUT", "an": 4}], "cunostinte": ["C", "C++", "SQL"] } | ||
- | |||
- | db.students.insert(stud) | ||
- | |||
- | var studs = [ | ||
- | {"student": { "firstname": "George", "lastname": "Popescu"}, "an": 4, "grupa": "341C2", "materii": [{"nume": "BD2", "an": 4}, {"nume": "IOCLA", "an": 2}], "cunostinte": ["Python", "SQL"] }, | ||
- | {"student": { "firstname": "Georgiana", "lastname": "Petrescu"}, "an": 4, "grupa": "341C2", "materii": [{"nume": "BD2", "an": 4}, {"nume": "SCAD", "an": 4}], "cunostinte": ["Python", "SQL"] }, | ||
- | {"student": { "firstname": "Valentina", "lastname": "Vasilescu"}, "an": 3, "grupa": "331CA", "materii": [{"nume": "BD", "an": 3}, {"nume": "RL", "an": 3}, {"nume": "APD", "an": 2}], "cunostinte": ["Java", "C++", "SQL"] }, | ||
- | {"student": { "firstname": "Grigore", "lastname": "Ionescu"}, "an": 4, "grupa": "342C2", "materii": [{"nume": "BD2", "an": 4}, {"nume": "VLSI", "an": 4}, {"nume": "SRIC", "an": 4}, {"nume": "SO", "an": 3}], "cunostinte": ["C", "Python", "SQL", "Ruby"] }, | ||
- | {"student": { "firstname": "Andrei", "lastname": "Popescu"}, "an": 3, "grupa": "332CA", "materii": [{"nume": "CN1", "an": 2}, {"nume": "CN2", "an": 2}, {"nume": "RL", "an": 3}], "cunostinte": ["C", "Python", "SQL", "Ruby"] }, | ||
- | {"student": { "firstname": "Ana", "lastname": "Georgescu"}, "an": 4, "grupa": "342C5", "materii": [{"nume": "BD2", "an": 4}, {"nume": "UBD", "an": 4}, {"nume": "SRIC", "an": 4}, {"nume": "SO", "an": 3}], "cunostinte": ["C", "Python", "SQL", "Ruby"], "sef": true }, | ||
- | ] | ||
- | |||
- | db.students.insert(studs) | ||
- | </code> | ||
- | |||
- | <color red>Ex. 4.</color> Inserați în baza de date **faculty** în colecția **students** folosind structura JSON de mai sus doi colegi și pe dumneavoastră. | ||
- | |||
- | === **mongoimport** === | ||
- | |||
- | Pentru a insera un fișier în format CSV sau JSON se folosește comanda **mongoimport**. | ||
- | Parametrii comenzii sunt: | ||
- | * ''-''''-host=<hostname><:port>'' - specifică numele host-ului și portul. Dacă nu se specifică se vor lua valorile implicite | ||
- | * ''-''''-port=<port>'' - specifică portul. Dacă nu se specifică se va lua valoarea implicită | ||
- | * ''-''''-db=<databasename>'' - specifică numele bazei de date unde se vor insera datele | ||
- | * ''-''''-collection=<collection>'' - specifică numele colecției care va stoca datele | ||
- | * ''-''''-fields=<field1[,field2]>'' - specifică câmpurile din fișier care for fi inserate în colecție | ||
- | * ''-''''-columnsHaveTypes'' - se utilizează dacă se dorește specificarea tipurilor de date pentru coloanele din lista de coloane specificată cu opțiunea ''-''''-fields'' | ||
- | * ''-''''-type=<json|csv|tsv>'' - specifică formatul fișierului cu date | ||
- | * ''-''''-file=<filename>'' - specifică numele fișierului cu date | ||
- | |||
- | |||
- | <code bash> | ||
- | mongoimport --host=192.100.10.2 --port=28018 --db=BD --collection=students --type=json --file=data_dump.json | ||
- | |||
- | mongoimport --host=192.100.10.2 --port=28018 --db=BD --collection=students --columnsHaveTypes --fields="name.string(),birthdate.date(2006-01-02),contacted.boolean(),followerCount.int32(),thumbnail.binary(base64)" --type=csv --file=data_dump.csv | ||
- | </code> | ||
- | |||
- | <color red>Ex. 5.</color> Să se insereze fișierul {{:bd2:laboratoare:bd2_mongo.txt|bd2_mongo}} care conține baza de date în format JSON. Noua bază de date se va numi **BD2** și colecția se va numi **documents**. | ||
- | |||
- | |||
- | ==== Selectarea datelor ==== | ||
- | |||
- | === Select === | ||
- | |||
- | În MongoDB operația de selecție a datelor este **find()** ([[https://docs.mongodb.com/manual/reference/method/db.collection.find/|Documentație]]). | ||
- | |||
- | Sintaxa comenzii este: | ||
- | |||
- | <code javascript> | ||
- | db.collection.find(query, projection) | ||
- | </code> | ||
- | |||
- | Unde | ||
- | * ''query'' reprezintă lista de filtre | ||
- | * ''projection'' reprezintă câmpurile care vor fi afișate | ||
- | |||
- | Dacă parametrul ''query'' lipsește, atunci se selectează toate documentele. Dacă parametrul ''projection'' lipsește atunci se afișează toate câmpurile documentului. | ||
- | |||
- | Comanda **find()** face paginație, arătând în consolă 10 înregistrări. | ||
- | |||
- | Să se selecteze toți studenții din colecția **students**, baza de date **faculty** | ||
- | <code javascript> | ||
- | db.students.find() | ||
- | </code> | ||
- | |||
- | |||
- | <note tip> | ||
- | * Dacă se dorește un întoarcerea unei singur document se folosește **findOne()** | ||
- | <code javascript> | ||
- | db.students.findOne() | ||
- | </code> | ||
- | |||
- | * Dacă se dorește un întoarcerea unui număr ''n'' de documente se folosește **limit(n)** | ||
- | <code javascript> | ||
- | db.students.find().limit(3) | ||
- | </code> | ||
- | |||
- | * Dacă se dorește sortarea rezultatelor după valoare unui anumit câmp se folosește ''sort({label_1: order, label_2: order,..., label_n:order})'' unde ''order'' este ''1'' pentru ascendent și ''-1'' pentru descendent. | ||
- | |||
- | <code javascript> | ||
- | db.students.find().sort({"grupa": 1}) | ||
- | </code> | ||
- | |||
- | * Dacă se dorește afișarea într-un mod citibil în consolă se folosește **pretty()** | ||
- | <code javascript> | ||
- | db.students.find().pretty() | ||
- | </code> | ||
- | |||
- | * **pretty**, **limit** și **sort** se pot folosi împreună | ||
- | |||
- | <code javascript> | ||
- | db.students.find().sort({"student.firstname": 1}).limit(3).pretty() | ||
- | </code> | ||
- | |||
- | </note> | ||
- | |||
- | <color red>Ex. 6.</color> Să se selecteze primele 4 rezultate ale unei cereri care întoarce toți studenți ordonați descrescător după nume. | ||
- | |||
- | |||
- | === Filtrarea cererilor === | ||
- | |||
- | Pentru a filtra rezultatele se folosește parametru **query**. | ||
- | |||
- | Pentru comparație avem: | ||
- | |||
- | * '':'' - egalitate | ||
- | * ''$ne'' - diferit de (not equal) | ||
- | * ''$gt'' - mai mare | ||
- | * ''$gte'' - mai mare sau egal | ||
- | * ''$lt'' - mai mic | ||
- | * ''$lte'' - mai mic sau egal | ||
- | * ''$in'' - căutare într-o listă | ||
- | * ''$all'' - căutare cu egalitate pe toate elementele dintr-o listă | ||
- | |||
- | |||
- | <code javascript> | ||
- | db.students.find({"student.firstname": "Ion"}) | ||
- | db.students.find({an: {$gte: 4}}) | ||
- | db.students.find({"materii.nume": {$in: ['SCAD', 'IA']} }) | ||
- | db.students.find({"grupa": /^341/ }) | ||
- | db.students.find({"cunostinte": {$all: [/^J/, /^C/ ]}}) | ||
- | </code> | ||
- | |||
- | Operatori logici | ||
- | * ''$or'' - sau logic | ||
- | * ''$and'' - și logic | ||
- | * ''$not'' - negare logic | ||
- | |||
- | |||
- | <code javascript> | ||
- | db.students.find({$or: [{"student.lastname": "Ionescu"}, {"cunostinte": /^C/}]}) | ||
- | db.students.find({$and: [{"student.lastname": "Ionescu"}, {"cunostinte": /^C/}]}) | ||
- | </code> | ||
- | |||
- | Operatori utili pentru vectori | ||
- | * ''$size'' pentru a verifica dimensiune | ||
- | * ''0, 1, 2,...'' pentru poziționare (indexare vectorilor începe de la 0) | ||
- | |||
- | |||
- | <code javascript> | ||
- | db.students.find({"cunostinte": {$size: 2}}) | ||
- | db.students.find({"cunostinte.2": "SQL"}) | ||
- | db.students.find({"materii.0.nume": "BD2"}) | ||
- | </code> | ||
- | |||
- | Pentru a verifica existența unui câmp se folosește ''$exists'' | ||
- | <code javascript> | ||
- | db.students.find({"sef": true}) | ||
- | db.students.find({"sef": {$exists: true}}) | ||
- | db.students.find({"sef": false}) | ||
- | db.students.find({"sef": {$exists: false}}) | ||
- | </code> | ||
- | |||
- | |||
- | <note important>Acești operatori pot să fie folosiți împreună.</note> | ||
- | |||
- | <color red>Ex. 7.</color> Explicați ce fac cererile din acest subcapitol. | ||
- | |||
- | <color red>Ex. 8.</color> Să se selecteze toți studenții din anul 4 care au restanțe și știu limbajele de programare C și SQL. | ||
- | |||
- | === Proiecția === | ||
- | |||
- | Pentru a proiecta doar anumite câmpuri se se folosește parametrul **projection**. | ||
- | În cazul în care nu se folosește filtrare se pun acolade fără goale pentru **query**. | ||
- | |||
- | <code javascript> | ||
- | db.students.find({}, {"student.firstname": 1}) | ||
- | </code> | ||
- | |||
- | O cerere cu **projection** va întoarce doar câmpurile specificate și ''_id''. Dacă se dorește să se elimine câmpul ''_id'' atunci proiecția trebuie să conțină și ''"_id": 0'' | ||
- | |||
- | <code javascript> | ||
- | db.students.find({}, {"_id": 0, "student.firstname": 1}) | ||
- | </code> | ||
- | |||
- | <color red>Ex. 9.</color> Să se selecteze studenții care nu sunt șefi și au cunoștințe de "Python" pe a doua poziție din vectorul de cunoștințe. Afișați doar numele, prenumele și vectorul de cunoștințe. | ||
- | |||
- | ==== Modificarea datelor ==== | ||
- | |||
- | Pentru a modifica datele se poate folosi una din comenzile: | ||
- | * ''db.collection.update(<query>, <update>, <options>)'' ([[https://docs.mongodb.com/manual/reference/method/db.collection.update/|Documentație]]) | ||
- | |||
- | Unde: | ||
- | * ''query'' - filtrează datele | ||
- | * ''update'' - setează date care trebuie modificate | ||
- | * ''options'' - diferite opțiuni, e.g.: | ||
- | * ''upsert: <boolean>'' - crează un nou document în cazul în care nu se găsește nici un document cu filtrul | ||
- | * ''multi: <boolean>'' - modifică mai multe documente | ||
- | |||
- | Pentru a seta o valoare se folosește ''$set'': | ||
- | <code javascript> | ||
- | db.students.update({"student.firstname": "George"}, {$set: {"grupa": "342C1"}}) | ||
- | db.students.update({an: 4, "student.firstname": "Grigore"}, {$set: {cunostinte: ["C++"]}}) | ||
- | </code> | ||
- | |||
- | Folosind set se suprascrie valoarea pentru câmp. În cazul în care dorim sa modificăm o structură de tip vector folosiți ''$push''. Dacă se dorește să se adauge mai multe valori, se poate folosi ''$push'' împreună cu ''$each''. | ||
- | <code javascript> | ||
- | db.students.update({an: 4, "student.firstname": "Grigore"}, {$push: {"cunostinte": "C"}}) | ||
- | db.students.update({an: 4, "student.firstname": "Grigore"}, {$push: {"cunostinte":{$each: ["Python", "SQL", "Ruby"]}}}) | ||
- | </code> | ||
- | |||
- | Dacă se dorește să se modifice valoare unui element dintr-o listă sau a unui câmp dintr-un document imbricat care se găsește în listă se poate folosi ''$''. Trebuie să selectați și valoare/câmpul care se dorește să fie modificat în ''query'': | ||
- | <code javascript> | ||
- | db.students.update({"student.firstname": "Grigore", "cunostinte": "C"}, {$set: {"cunostinte.$": "Java"}}) | ||
- | db.students.update({"student.firstname": "Grigore", "materii.nume": "SRIC"}, {$set: {"materii.$.nume": "SPG"}}) | ||
- | db.students.update({"student.firstname": "Grigore", "materii.nume": "SPG"}, {$set: {"materii.$.nume": "SRIC", "materii.$.an":4}}) | ||
- | </code> | ||
- | |||
- | <color red>Ex. 10.</color> Să se adauge la toți studenți de anul 3 materiile EGC și LFA (nume si an) folosind o singură comandă. | ||
- | |||
- | |||
- | |||
- | Alte funcții care modifică datele sunt: | ||
- | * ''db.collection.updateOne(<query>, <update>, <options>)'' | ||
- | * ''db.collection.updateMany(<query>, <update>, <options>)'' | ||
- | * ''db.collection.updateMany(<query>, <update>, <options>)'' | ||
- | |||
- | |||
- | ==== Ștergerea datelor ==== | ||
- | Pentru a șterge un document dintr-o colecție se folosește comanda: | ||
- | * ''db.collection.remove(<query>, <justOne>)'' [[https://docs.mongodb.com/manual/reference/method/db.collection.remove/|Documentație]] | ||
- | |||
- | Unde | ||
- | * ''query'' - filtrează datele | ||
- | * ''justOne'' - boolean pentru a șterge unul (''true'') sau mai multe (''false'' -- implicit) documente | ||
- | |||
- | <code javascript> | ||
- | db.students.remove({"an": {$lt: 4}}) | ||
- | </code> | ||
- | |||
- | <note important> | ||
- | Pentru a șterge toate documentele se folosește ''db.collection.remove({})'' | ||
- | <code javascript> | ||
- | db.students.remove({}) | ||
- | </code> | ||
- | </note> | ||
- | |||
- | Alte comenzi care pot fi utilizare pentru a șterge documente dintr-o colecție sunt: | ||
- | * ''db.collection.deleteOne(<filter>)'' | ||
- | * ''db.collection.deleteMany(<filter>)'' | ||
- | |||
- | <color red> Ex. 11.</color> Să se șteargă doar un student care are materia BD2. | ||
- | |||
- | ===== Indexare ===== | ||
- | |||
- | MongoDB suport diferite tipuri de indecși. Indecși sunt utilizați pentru a crește performanțele operațiilor de căutare. Indecși sunt creați la nivel de colecție. Pentru a crea un index se folosește comanda ''createIndex()''. La creare se specifică numele câmpului (i.e., ''label'') și modul de ordonare a indexului (i.e., ''order'') | ||
- | * Indecși simpli ''db.collection.createIndex({"label": order})'' | ||
- | * Indecși compusi ''db.collection.createIndex({"label_1": order_1, "label_2": order_2, ...})'' | ||
- | * Indecși pe documente imbricate: ''db.collection.createIndex({"label_1.nested_label": order_1, "label_2.nested_label": order_2, ...})'' | ||
- | * Indecși geo-spațiali ''db.collection.createIndex({"label_1.nested_label": "2d"})'' | ||
- | * Indecși textuali (o colecție poate să aibă un singur index textual, dar acesta poate fi compus)''db.collection.createIndex({"label_1": "text", "label_2": "text", ...})'' | ||
- | * Indecși hashed (utili pentru sharding): ''db.collection.createIndex({"label": "hashed"})'' | ||
- | |||
- | Pentru următoarele exemple conectați-vă la baza de date **BD2** creată anterior cu **mongoinport**. | ||
- | |||
- | <color red>Ex. 12.</color> Analizați schema documentelor și înțelegeți structura | ||
- | |||
- | <code javascript> | ||
- | db.documents.createIndex({author: 1}) | ||
- | db.documents.createIndex({gender: 1, age: 1}) | ||
- | db.documents.createIndex({"words.word": 1}) | ||
- | db.documents.createIndex({"geoLocation": "2d"}) | ||
- | db.documents.createIndex({"lemmaText": "text"}) | ||
- | db.documents.createIndex({"date": "hashed"}) | ||
- | </code> | ||
- | |||
- | <color red>Ex. 13.</color> Descrieți tipul indecșilor construiți anterior. | ||
- | |||
- | <note important> | ||
- | Pentru a vedea toți indecși se folosește comanda ''db.collection.getIndexes()'' | ||
- | |||
- | Pentru a șterge un index se folosește comanda ''db.collection.dropIndexes("index_name")'' | ||
- | |||
- | Pentru a șterge toți indecși (cu excepția indexului de pe cheia primară) se folosește comanda ''db.collection.dropIndexes()'' | ||
- | </note> | ||
- | |||
- | ==== Utilizare indecși geo-spațiali ==== | ||
- | |||
- | * Pentru a găsi documentele de lângă un punct ''p=[x, y]'' se folosește ''$near'' | ||
- | * Pentru a găsi documentele care se găsesc în diferite figuri geometrice se folosește ''$within'': | ||
- | * Pentru un cerc cu centrul într-un punct ''p=[x, y]'' și o rază ''r'' se folosește ''$center'' | ||
- | * Pentru un dreptunghi definit prin punctele din stânga jos și dreapta sus se folosește ''$box'' | ||
- | * Pentru un poligon dat de o listă puncte se folosește ''$polygon'' | ||
- | |||
- | <code javascript> | ||
- | db.documents.find( { geoLocation: { $near: [25, 25] } }, {geoLocation: 1} ) | ||
- | db.documents.find( { geoLocation: { $within: { $center: [[25, 10], 3] } } }, {geoLocation: 1} ) | ||
- | db.documents.find( { geoLocation: { $within: { $box: [[25, 40], [30, 45]] } } }, { geoLocation: 1 } ) | ||
- | db.documents.find( { geoLocation: { $within: { $polygon: [[20, 40], [40, 50], [30, 30]] } } }, { geoLocation: 1 } ) | ||
- | </code> | ||
- | |||
- | ==== Utilizare indecși textuali ==== | ||
- | |||
- | Pentur a utiliza un index textual se folosește următoare sintaxă: | ||
- | <code javascript> | ||
- | { | ||
- | $text: | ||
- | { | ||
- | $search: <string>, | ||
- | $language: <string>, | ||
- | $caseSensitive: <boolean>, | ||
- | $diacriticSensitive: <boolean> | ||
- | } | ||
- | } | ||
- | </code> | ||
- | |||
- | Unde | ||
- | * ''$search'' - este șirul de cuvinte căutat sau fraza căutată | ||
- | * ''$language'' - este limba pentru cuvintele căutate | ||
- | * ''$caseSensitive'' - dacă se caută case sensitive sau nu | ||
- | * ''$diacriticSensitive'' - dacă se ține cont de diacritice sau nu | ||
- | |||
- | |||
- | <code javascript> | ||
- | # Caută un cuvânt | ||
- | db.documents.find( { $text: { $search: "coffee", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } , { lemmaText: 1 } ) | ||
- | |||
- | # Caută mai multe cuvinte (se folosește operatorul or) | ||
- | db.documents.find( { $text: { $search: "coffee cup", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } , { lemmaText: 1 } ) | ||
- | |||
- | # Caută o frază | ||
- | db.documents.find( { $text: { $search: "\"heaven tonight\"", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } , { lemmaText: 1 } ) | ||
- | |||
- | # Caută o frază cu un scor de relevanță | ||
- | db.documents.find( { $text: { $search: "\"heaven tonight\"", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } , { score: { $meta: "textScore" }, lemmaText: 1, _id: 0}) | ||
- | </code> | ||
- | |||
- | <color red>Ex. 14.</color> Să se găsească toate documentele care se află într-un dreptunghi dat de punctele ''[20, -100]'' și ''[40, 90]'', care să conțină cuvintele **tech** și **engineering**. Cererea să se folosească de indexul textual. Afișeți câmpul **rawText**. Să se refacă cererea utilizând alt câmp din document. | ||
- | |||
- | ===== Funcții ===== | ||
- | |||
- | MongoDB permite dezvoltatorilor sa scrie funcții folosind limbajul JavaScript. | ||
- | |||
- | <color red>Ex. 15.</color> Să se scrie o funcție care primește un **query** pentru filtrare și împarte **lemmaText** în cuvinte. Funcția va întoarce un vector. | ||
- | |||
- | <code javascript> | ||
- | tokenization = function(q){ | ||
- | var cursor = db.documents.find(q,{"_id": 0, lemmaText: 1}); | ||
- | var tokens = Array(); | ||
- | cursor.forEach(function(elem){ | ||
- | tokens = tokens.concat(elem["lemmaText"].split(" ")); | ||
- | }); | ||
- | return tokens; | ||
- | } | ||
- | |||
- | // utilizate | ||
- | var q = {gender: "male"} | ||
- | tokens = tokenization(q) | ||
- | |||
- | </code> | ||
- | |||
- | <color red>Ex. 16.</color> Să se scrie o funcție numită **countWords** care primește un **query** pentru filtrare și numără aparițiile unui cuvânt. Funcția va întoarce un obiect de forma ''{word_1: count, word_2: count, ...}''. Folosiți funcția ''tokenization''. | ||
- | |||
- | |||
- | ===== Funcții stocate ===== | ||
- | |||
- | Funcțiile pot fi stocate la nivelul MongoDB. Pentru acest lucru se folosește o colecție specială numită ''system.js''. Stocarea se face cu comanda: ''db.system.js.save(_id: "function_name", value: "function_body")''. Pentru a lucra cu funcțiile stocare (a le încărca în sesiune) se folosește comanda ''db.loadServerScripts()''. | ||
- | |||
- | <code javascrit> | ||
- | db.system.js.save( | ||
- | { | ||
- | _id: "tokenization", | ||
- | value : function(q){ | ||
- | var cursor = db.documents.find(q,{"_id": 0, lemmaText: 1}); | ||
- | var tokens = Array(); | ||
- | cursor.forEach(function(elem){ | ||
- | tokens = tokens.concat(elem["lemmaText"].split(" ")); | ||
- | }); | ||
- | return tokens; | ||
- | } | ||
- | } | ||
- | ) | ||
- | |||
- | db.loadServerScripts() | ||
- | </code> | ||
- | |||
- | <color red>Ex. 17.</color> Salvați și apoi încărcați în sesiune funcția **countWords**. | ||
- | |||
- | ===== Agregarea datelor ===== | ||
- | |||
- | În MongoDB putem să agregăm datele folosind mai multe metode: | ||
- | * Funcții de agregare | ||
- | * Modulul nativ de Aggregation Pipeline | ||
- | * MapReduce | ||
- | |||
- | ==== Funcții de agregare ==== | ||
- | |||
- | MongoDB oferă utilizatorilor două funcții pentru agregare: | ||
- | |||
- | 1. Count: ''db.collection.count(query)'' | ||
- | |||
- | <code javascript> | ||
- | // Cate documente au lungimea textului lematizat 10 | ||
- | db.documents.count({lemmaTextLength: 10}) | ||
- | </code> | ||
- | | ||
- | |||
- | 2. Distinct: db.collection.distinct(field, query) | ||
- | |||
- | <code javascript> | ||
- | // afiseaz varstele distincte | ||
- | db.documents.distinct("age") | ||
- | |||
- | // afiseaz varstele distincte pentru female | ||
- | db.documents.distinct("age", {gender: "female"}).sort() | ||
- | </code> | ||
- | | ||
- | <color red>Ex. 18.</color> Afișați toate cuvintele distincte. Folosiți câmpul **words**. | ||
- | |||
- | ==== Aggregation Pipeline ==== | ||
- | |||
- | Pentru agregare, MongoDB oferă și **Aggregation Pipeline** ([[https://docs.mongodb.com/manual/core/aggregation-pipeline/|Documentație]]). | ||
- | |||
- | <code javascript> | ||
- | db.collection.aggregate( | ||
- | { $match: <query> }, | ||
- | { $unwind: <array> }, | ||
- | { $project: <projection>}, | ||
- | { $group: <aggregation_group, aggregation_functions> }, | ||
- | { $sort: <sorting_fields> }, | ||
- | ) | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * $match - filtrează documentele de intrare după un **query** | ||
- | * $unwind - procesează elementele unui vector | ||
- | * $project - proiecția | ||
- | * $group - face grupuri și a aplica funcții agregare | ||
- | * $sort - reordonează documentele de intrare după o cheie | ||
- | |||
- | <note important>Contează ordinea în care sunt folosiți operatorii.</note> | ||
- | |||
- | <color red>Ex. 19.</color> Să se utilizeze Aggregation Pipeline pentru a calcula numărul de apariții ale cuvintelor. | ||
- | |||
- | <code javascript> | ||
- | db.documents.aggregate([ | ||
- | { $match: q }, | ||
- | { $project: { words: { $split: ["$lemmaText", " "]}}}, | ||
- | { $unwind: "$words" }, | ||
- | { $group: { _id: "$words", counts: { $sum: 1 } } } | ||
- | ]) | ||
- | </code> | ||
- | |||
- | <color red>Ex. 20.</color> Să se utilizeze Aggregation Pipeline pentru a calcula numărul de apariții ale cuvintelor folosind coloana **words**. | ||
- | |||
- | ==== MapReduce ==== | ||
- | |||
- | MongoDB oferă un framework de MapReduce. Pentru a utiliza acest framework trebuie să scriem două funcții,i.e., Map și Reduce. | ||
- | Pentru a utilza funcțiile pe o colecție se folosește ''mapReduce'' ([[https://docs.mongodb.com/manual/core/map-reduce/|Documentație]]): | ||
- | |||
- | |||
- | <code javascript> | ||
- | |||
- | db.collection.mapReduce( | ||
- | mapFunction, | ||
- | reduceFunction, | ||
- | { | ||
- | finalize: <function>, | ||
- | out: <output>, | ||
- | query: <document>, | ||
- | sort: <document>, | ||
- | limit: <number>, | ||
- | scope: <document> | ||
- | } | ||
- | ) | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * mapFunction - funcția de map | ||
- | * reduceFunction - funcția de reduce | ||
- | * finalize - (opțional) funcție pentru finalizare, se aplică după ce se termină procesul și datele sunt agregate | ||
- | * out - (opțional) colecția unde va fi salvat rezultatul | ||
- | * query - (opțional) filtru pentru documentele de intrare | ||
- | * sort - (opțional) ordonează documentele de intrare după cheie | ||
- | * limit - (opțional) limitează numărul de documente de intrare | ||
- | * scope - (opțional) variabile din exterior care pot fi folosite în funcțiile map, reduce și finalize | ||
- | |||
- | Comanda ''mapReduce'' este o mapare peste comanda **mapReduce** din MongoDB ([[https://docs.mongodb.com/manual/reference/command/mapReduce/|Documentație]]) | ||
- | |||
- | <code javascript> | ||
- | db.runCommand( | ||
- | { | ||
- | mapReduce: <collection>, | ||
- | map: <function>, | ||
- | reduce: <function>, | ||
- | finalize: <function>, | ||
- | out: <output>, | ||
- | query: <document>, | ||
- | sort: <document>, | ||
- | limit: <number>, | ||
- | scope: <document> | ||
- | } | ||
- | ) | ||
- | </code> | ||
- | |||
- | |||
- | <color red>Ex. 21.</color> Să se utilizeze MapReduce pentru a calcula numărul de apariții ale cuvintelor. | ||
- | |||
- | <code javascript> | ||
- | mapFunction = function() { | ||
- | var tokens = this.lemmaText.split(" "); | ||
- | for (var idx=0; idx<tokens.length; idx++){ | ||
- | emit(tokens[idx], 1); | ||
- | } | ||
- | } | ||
- | | ||
- | reduceFunction = function(key, values) { | ||
- | return Array.sum(values); | ||
- | }; | ||
- | | ||
- | var q = {"gender": "female"} | ||
- | db.documents.mapReduce(mapFunction, reduceFunction, {query: q, out: "wordCounts"}); | ||
- | |||
- | db.wordCounts.count() | ||
- | |||
- | db.wordCounts.find({"_id": "0"}) | ||
- | |||
- | db.wordCounts.drop() | ||
- | </code> | ||
- | |||
- | <color red>Ex. 22.</color> Să se utilizeze MapReduce pentru a calcula numărul de apariții ale cuvintelor folosind câmpul **words**. |