====== Accedint a MongoDB ======
MongoDB és una base de dades no-SQL orientada a document.
Aquest article està orientat a la connexió a MongoDB a través de diferents llenguatges de programació.
Es recomana utilitzar una versió avançada de MongoDB. Si la versió de MongoDB és 2.x o menor, algunes eines com Robomongo o Studio 3T no ens funcionaran bé. A Ubuntu 18.04 hi ha MongoDB > 3.x, cap problema, doncs (però a Ubuntu 16.04 tenien versions 2.x i no eren viables).
Recursos:
* Tens [[https://cacauet.org/wiki/index.php/MongoDB|apunts de MongoDB a cacauet.org]]
* [[https://tecadmin.net/install-mongodb-on-ubuntu/|Instal·lar MongoDB a Ubuntu]].
* https://robomongo.org facilita la gestió i fer proves, tot i que la //shell// de MongoDB és força còmoda ja que utilitza JavaScript com a llenguatge nadiu.
* [[https://www.mongodb.com/cloud/atlas|Mongo Atlas]] és un servei de BD Mongo al núvol que ens permet un cluster gratuït.
{{mdb-vs-sql.png?direct}}
Importa amb ''mongorestore'' la base de dades de prova {{movies-mongo-dump.rar}}. La utilitat d'importació habitual és ''mongoimport'', però en aquest cas farem servir ''mongorestore'' ja que les dades estan en format binari).
{{tag> #FpInfor #Dam #DamMp06 #DamMp06Uf3 #DamMp06Uf03 #Daw #DawMp07 #DawMp07Uf3 #DawMp07Uf03 nodejs mongodb mongo node nosql bbdd }}
\\
===== MongoDB i PHP =====
==== Instal·lació ====
Primer cal [[https://docs.mongodb.com/ecosystem/drivers/php/|instal·lar el //driver// tal i com s'explica a la documentació]]. (Adaptar aquestes ordres a la versió adequada si fos necessari: p.ex. php-dev podria ser php7.2-dev ).
Per Ubuntu LTS això funcionaria:
$ sudo apt install php-dev php-pear
$ sudo pecl install mongodb
Afegim la llibreria a la instal·lació afegint a l'arxiu ''php.ini'':
extension=mongodb.so
Cal mirar la [[https://www.php.net/manual/es/book.mongodb.php|documentació de la llibreria]].
==== Exemple MongoDB amb PHP ====
Suposant una col·lecció bàsica com aquesta:
{
"_id" : ObjectId("5e1b40a2d7a590a8d1709ab7"),
"marca" : "Renault",
"model" : "Twizzy"
}
{
"_id" : ObjectId("5e1b40add7a590a8d1709ab8"),
"marca" : "Seat",
"model" : "León"
}
Cal mirar bé la documentació de PHP perquè hi ha diversos //drivers// i s'utilitzen de forma diferent. El què hem instal·lat correspon a aquesta doc: https://www.php.net/manual/es/book.mongodb.php
Aquest ens ha funcionat amb el següent exemple:
use MongoDB\Driver\Manager as MongoManager;
use MongoDB\Driver\Query as MongoQuery;
$mongo = new MongoManager();
$filter = [];
$options = [];
$query = new MongoQuery( $filter, $options );
$cotxes = $mongo->executeQuery( "prova.cotxes", $query );
foreach( $cotxes as $cotxe ) {
echo $cotxe->marca." ".$cotxe->model."
\n";
}
\\
===== MongoDB amb NodeJS =====
Importa amb ''mongorestore'' la base de dades de prova {{movies-mongo-dump.rar}}.
Per saber més de NodeJS mira't els apunts a [[nodejs_express]].
==== Instal·lació ====
Per connectar-nos disposem del [[https://mongodb.github.io/node-mongodb-native/3.5/quick-start/quick-start/|Driver asíncron (mongodb)]] per a JavaScript. Pots instal·lar-lo amb
$ npm install mongodb
Les classes principals que utilitzarem són [[https://mongodb.github.io/node-mongodb-native/3.5/api/Cursor.html#toArray|Cursor]] i [[https://mongodb.github.io/node-mongodb-native/3.5/api/Collection.html|Collection]]
Els [[https://mongodb.github.io/node-mongodb-native/3.5/reference/cursors/|cursors ben explicats aquí]].
==== Connection Pooling ====
Per gestionar les connexions a MongoDB dins d'una aplicació web (concorrent per natura) es recomana fer 1 sola connexió per la //app//, i reutilitzar l'element ''db'' en cada //request//. Això ens proveirà el que anomenem [[http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connection-pooling|connection pooling]]. El //driver// és intel·ligent i sap gestionar les diverses connexions de la forma més òptima per paral·lelitzar els accessos del servidor web.
Per inicar el projecte node, crea **dins d'una carpeta**:
$ npm init
$ npm install express body-parser ejs mongodb
Afegeix el codi a index.js i arrenca el servidor:
$ node index.js
==== Codi d'exmeple NodeJS i MongoDB ====
[[https://mongodb.github.io/node-mongodb-native/3.5/reference/cursors/|Doc inicial sobre les collections i cursors]] de MongoDB.
Exmple de connexió per a una pàgina web:
// framework express
var express = require('express');
// bodyparser ens permet processar variables GET i POST
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
// per renderitzar les plantilles (render)
app.set('view engine','ejs');
var mongo = require('mongodb').MongoClient;
var mongoClient;
// connexió a mongo i start app
mongo.connect('mongodb://localhost:27017', function( err, _client ) {
// si no ens podem connectar, sortim
if( err ) throw err;
mongoClient = _client;
// si no hi ha cap error de connexió, engeguem el servidor
app.listen(3000, function () {
console.log('Example app listening on http://localhost:3000 !');
});
});
// view: llistat elements
app.get('/', function (req, res) {
var db = mongoClient.db("cotxes");
var opcions = {};
var query = {};
db.collection('cotxes').find( query, opcions ).toArray(function( err, docs ) {
if( err ) {
res.render( 'error', {msg:"error a la query"} );
return;
}
// renderitzem la plantilla q hem de crear a views/cotxes.ejs
res.render( 'cotxes', {"cotxes":docs} );
});
});
// view: llistat elements en format JSON (API)
app.get('/api/movies', function (req, res) {
var db = mongoClient.db("video");
var fields = { _id:true, title:true, year:true };
var query = {};
var opcions = { limit:4, fields:fields };
db.collection('movieDetails').find( query, opcions ).toArray(function( err, docs ) {
if( err ) {
res.send( JSON.stringify( {status:"error",msg:"error a la query"}) );
return;
}
// transformem l'array "docs" en un string i el retornem tal qual
res.send( JSON.stringify(docs) );
});
});
Visita la web amb el browser a (cal abans crear les plantilles ejs descrites més avall)
http://localhost:3000
Prova la API amb la comanda:
$ curl localhost:3000/api/movies
A aquest codi caldrà afegir les **plantilles ''error.ejs'' i ''cotxes.ejs'' a la carpeta ''views''** que renderitzarà finalment la llista de cotxes que ens ha retornat a ''docs''.
https://mongodb.github.io/node-mongodb-native/3.5/tutorials/collections/
És important remarcar que
* ''db.collection().find()'' ens retorna un [[https://mongodb.github.io/node-mongodb-native/3.5/reference/cursors/|Cursor]]. Els cursors és una mena de punter a la BD. No carreguen totes les dades en memòria.
* Detalls de la [[https://mongodb.github.io/node-mongodb-native/api-generated/collection.html#find|funció find()]]
* ''db.collection().find().toArray()'' ens retorna un array amb les dades extretes. Abans de cridar ''toArray'' hem d'estar segurs que tindrem prou memòria RAM per poder emmagatzemar les dades. Fer una query que retorni molts resultats pot ser perillós ja que podria saturar el servidor.
==== ObjectID ====
De vegades voldrem accedir a diferents elements de la llibreria de MongoDB per a NodeJS. Per exemple, [[https://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html|per generar ObjectIDs fes un cop d'ull a aquest codi]].
\\
===== Connectant amb MongoDB Atlas =====
Obriu-vos un compte a [[https://www.mongodb.com/cloud/atlas|MongoDB Atlas]] que us permetrà crear un //cluster// MongoDB gratuït al núvol. Importeu les col·leccions d'exemple per poder fer proves.
Si busqueu com connectar al vostre //cluster//, us mostrarà un string del tipus:
mongodb+srv://pepe:pepe123@cluster0-metgf.mongodb.net/mydb
... que significa que em puc connectar a l'usuari "pepe" amb password "pepe123" i accedir a la BD "mydb".
Modifiqueu el codi de l'aplicació perquè us connecti a la vostra instància Atlas. Penseu que no podeu crear un codi que contingui usuaris i contrasenyes i pujar-ho al sistema de control de versions (GitHub), ja que l'exposaríeu a altres usuaris i us hackejarien la base de dades fàcilment. Així, una bona pràctica de control de versions és posar el usuari i //password// del nostre cluster a les variables d'entorn, i al codi capturar-ho amb ''process.env.MYVAR'':
Abans d'engegar l'aplicació haureu de ajustar les variables d'entorn amb
$ export DBUSER=admin
$ export DBPASS=P@ssw0rd
$ node app.js
// connexió a mongo i start app
var mongo = require('mongodb').MongoClient;
var mongoClient;
// consts
const PORT = process.env.PORT || 5000
const user = encodeURIComponent( process.env.DBUSER );
const pass = encodeURIComponent( process.env.DBPASS );
var dbConStr = "mongodb+srv://"+user+":"+pass+"@cluster0-metgf.mongodb.net/grades";
mongo.connect( dbConStr, function( err, _client ) {
// si no ens podem connectar, sortim
if( err ) throw err;
mongoClient = _client;
// si no hi ha cap error de connexió, engeguem el servidor
app.listen(PORT, function () {
console.log('Example app listening on http://localhost:'+PORT+' !');
});
});
==== Contrasenyes segures ====
Aquest codi anterior captura les variables DBUSER i DBPASS de l'entorn de la //shell//, la qual cosa va bé, però resulta una mica incòmode ajustar les variables cada cop que engeguem la màquina. Per estalviar-nos aquest pas, podem posar les variable a l'arxiu ''.env'', però **afegint ''.env'' al ''.gitignore'' per evitar que pugem aquest arxiu amb contasenyes al repositori de codi**.
Utilitza el [[https://www.npmjs.com/package/dotenv|paquet dotenv de npm]] per carregar les variables d'entorn de l'arxiu ''.env''. Tindrem un arxiu '.env' com ara:
DBUSER=user
DBPASS=P@ssw0rd
I podem carregar-lo tal i com diu la documentació, amb:
require('dotenv').config()
\\
===== Exercici DB films =====
Importa amb ''mongorestore'' la base de dades de prova {{movies-mongo-dump.rar}}.
Crea una web amb la base de dades de films que implementi:
- Visualització de llistat de pel·lícules paginades en grups de 6 per pàgina (configurable per una variable global).
- Possibilitat d'avançar i retrocedir en les pàgines.
- Mostrar la imatge indicada en el camp "poster" de la col·lecció movieDetails.
- Que mostri la descripció de la pel·lícula (camp "plot"), a més del títol.
- Habilitar botoó "edita" que permeti editar el títol i la descripció de la pel·lícula.
- Implementar una cerca entre els títols de pel·lícula per filtrar.
- Ampliar que les cerques també mirin als actors, directors i escriptors (//writers//).
- Implementar un sistema de valoracions de la pel·lícula (del 0 al 10 ).
- Filtrar que només es pugui valorar un cop amb el ID del cookie de sessió (quan canvia de IDsession es pot tornar a votar).
\\