PR507403 — MongoDB amb Docker
Tipus: Pràctica tècnica (Docker + MongoDB) Durada estimada: 9 hores (3 sessions de 3 hores) Lliurament: Campus Virtual — Script(s) Mongo + captures + informe breu
Objectius
Al finalitzar aquesta pràctica, l'alumne serà capaç de:
- Instal·lar i configurar una instància de MongoDB amb Docker i connectar-s'hi amb MongoDB Compass i
mongosh. - Dissenyar l'esquema de documents per a un cas d'ús d'e-commerce, justificant les decisions d'embedding vs referencing per a cada relació.
- Implementar operacions CRUD completes (insertOne/insertMany, find, updateOne/updateMany, deleteOne/deleteMany) i consultes amb operadors de filtre, lògics i sobre arrays.
- Construir pipelines d'agregació amb
$match,$group,$project,$lookupi$unwindper respondre preguntes analítiques reals sobre el negoci. - Crear índexs simples, compostos i de text adequats als patrons d'accés de l'aplicació, i verificar-ne l'impacte real amb
explain(). - Interpretar la sortida d'
explain()per distingir unCOLLSCANd'unIXSCANi argumentar quan un índex és útil.
Materials necessaris
- Docker Desktop (o Docker Engine + Docker Compose) instal·lat i funcionant.
- MongoDB Compass instal·lat.
- Un editor de codi (VS Code recomanat) amb l'extensió MongoDB per a sintaxi
.js. - Els continguts del Bloc 3, que cal tenir oberts com a referència:
- Fonaments de MongoDB — model de documents, BSON, embedding vs referencing.
- Queries i CRUD —
mongosh, operadors de filtre, projecció. - Aggregation Pipeline —
$match,$group,$lookup,$unwind. - Índexs i rendiment — tipus d'índex,
explain(), cardinalitat.
Pràctica tècnica
A diferència de la pràctica del Bloc 1, aquí cal instal·lar programari, escriure codi JavaScript (mongosh) i executar comandes Docker. Si no has completat les miniactivitats AC5074/03/01 a AC5074/03/04 del bloc, fes-les abans de començar aquesta pràctica.
Descripció de la pràctica
Part 1 — Instal·lació de MongoDB amb Docker (1 hora)
Crea un directori de treball pr507403-nom_cognom/ amb l'estructura següent:
pr507403-nom_cognom/
├── docker-compose.yml
├── scripts/
│ ├── 01_carrega_dades.js
│ ├── 02_crud_queries.js
│ ├── 03_aggregation.js
│ └── 04_indexos.js
└── informe/
└── informe_pr507403.md
Crea el fitxer docker-compose.yml amb un servei MongoDB i un servei Mongo Express (eina web opcional per inspeccionar la BD des del navegador):
# docker-compose.yml
services:
mongodb-nom-cognom:
image: mongo:7
container_name: mongodb-nom-cognom
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin123
MONGO_INITDB_DATABASE: bigdata_nom_cognom
ports:
- "27017:27017"
volumes:
- mongodata_nom_cognom:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
mongo-express-nom-cognom:
image: mongo-express:latest
container_name: mongo-express-nom-cognom
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: admin
ME_CONFIG_MONGODB_ADMINPASSWORD: admin123
ME_CONFIG_MONGODB_SERVER: mongodb-nom-cognom
ME_CONFIG_BASICAUTH_USERNAME: admin
ME_CONFIG_BASICAUTH_PASSWORD: admin123
ports:
- "8081:8081"
depends_on:
mongodb-nom-cognom:
condition: service_healthy
volumes:
mongodata_nom_cognom:
Aixeca els serveis i verifica que tot funciona:
docker compose up -d
docker compose ps
# Connectar-se via mongosh dins del contenidor
docker exec -it mongodb-nom-cognom mongosh \
--username admin --password admin123 --authenticationDatabase admin
Connecta't també amb MongoDB Compass fent servir la cadena de connexió mongodb://admin:admin123@localhost:27017 i confirma que pots veure les bases de dades del servidor.
Lliurable de la Part 1: captura de pantalla de docker compose ps amb els dos serveis en estat healthy/running i captura de Compass connectat al servidor.
Part 2 — Disseny de l'esquema per a l'e-commerce (2 hores)
Cas d'ús: Sapa-Shop
Reutilitzem el cas d'ús Sapa-Shop (e-commerce d'electrònica) ja conegut del Bloc 1. Cal dissenyar tres col·leccions: productes, clients i comandes.
2.1 Col·lecció productes
Catàleg de productes amb especificacions tècniques variables segons la categoria (camp niuat especificacions, exemple ja vist a Fonaments de MongoDB):
{
_id: "PRD-010",
nom: "Portàtil Lenovo ThinkPad",
categoria: "informatica",
preu: 899.99,
estoc: 15,
valoracio: 4.7,
tags: ["portàtil", "treball", "professional"],
especificacions: {
processador: "Intel i7",
ram_gb: 16,
disc_gb: 512
},
disponible: true,
data_alta: ISODate("2025-01-10")
}
2.2 Col·lecció clients
{
_id: "CLI-001",
nom: "Joan Puig",
email: "joan.puig@exemple.cat",
segment: "premium",
adreces: [
{ tipus: "facturacio", carrer: "Carrer Major 12", ciutat: "Girona", cp: "17001" },
{ tipus: "enviament", carrer: "Avinguda Pau 5", ciutat: "Blanes", cp: "17300" }
],
data_registre: ISODate("2023-04-02")
}
2.3 Col·lecció comandes
Cada comanda referencia el client (per client_id) però embedeix les línies de producte amb una còpia del nom i preu en el moment de la compra (patró habitual en e-commerce: el preu d'una comanda passada no ha de canviar si el producte canvia de preu després):
{
_id: ObjectId("..."),
numero_comanda: "CMD-2026-00321",
client_id: "CLI-001",
data: ISODate("2026-03-12"),
linies: [
{ producte_id: "PRD-010", nom: "Portàtil Lenovo ThinkPad", preu_unitari: 899.99, quantitat: 1 },
{ producte_id: "PRD-045", nom: "Ratolí Logitech MX Master", preu_unitari: 89.99, quantitat: 2 }
],
total: 1079.97,
estat: "completat",
pais_enviament: "Espanya"
}
Tasques:
- Justifica per escrit (al fitxer
informe_pr507403.md) la decisió d'embedding vs referencing per a cadascuna d'aquestes relacions:comanda → client,comanda → línies de producte,client → adreces. Usa la taula de decisió d'embedding vs referencing com a referència. - Identifica almenys un possible anti-patró que podries cometre en aquest disseny (per exemple, embedding il·limitat de l'historial de comandes dins del document de client) i explica com l'evites.
- Escriu l'script
scripts/01_carrega_dades.jsque crea la base de dadesbigdata_nom_cognomi insereix, ambinsertMany, com a mínim 20 productes (almenys 4 categories diferents), 10 clients i 30 comandes (amb dates repartides entre gener i juny de 2026 i estats"completat","pendent"o"cancel·lat").
Generar dades de mostra ràpidament
No cal escriure els 60 documents a mà. Pots generar-los amb un bucle for dins del mateix script mongosh, variant categoria, preu i data amb Math.random(), o amb un petit script Python (pymongo) si ho prefereixes. L'important és que les dades siguin variades i permetin respostes interessants als pipelines de la Part 4.
Part 3 — CRUD i queries amb operadors (2 hores)
Escriu a scripts/02_crud_queries.js les operacions següents sobre les col·leccions creades a la Part 2 (consulta Queries i CRUD per a la sintaxi completa):
- Create: insereix un nou producte amb
insertOnei tres comandes noves ambinsertMany. - Read — operadors de comparació: productes amb preu entre 50 € i 300 € (
$gte/$lte), de les categories"informatica"o"monitors"($in). - Read — operadors lògics: comandes amb estat
"completat"i total superior a 200 € ($andimplícit); productes amb valoració superior a 4.5 o que tinguin el tag"oferta"($or). - Read — documents niuats i arrays: clients amb una adreça d'enviament a
"Blanes"(notació punt sobre l'arrayadrecesamb$elemMatch); comandes que continguin una línia ambproducte_id: "PRD-010"($elemMatch). - Read — expressions regulars: productes el nom dels quals contingui
"Pro"o"pro"($regexamb l'opció"i"). - Read — projecció i ordenació: els 5 productes més cars, mostrant només
nom,preuicategoria. - Update: aplica un descompte del 15% (
$mul) a tots els productes de la categoria"peripherics"; afegeix el tag"top-vendes"($addToSet) als 3 productes amb més valoració. - Upsert: actualitza (o crea si no existeix) un producte concret pel seu nom.
- Delete: elimina les comandes amb estat
"cancel·lat"i una antiguitat superior a 6 mesos. - Documenta a l'informe quin operador SQL equivaldria a cadascuna de les operacions anteriors (taula de dues columnes).
Part 4 — Aggregation Pipeline (2 hores)
Escriu a scripts/03_aggregation.js els pipelines següents (consulta Aggregation Pipeline):
4.1 Vendes per categoria. Pipeline amb $match (comandes "completat"), $unwind de linies, $lookup amb productes per obtenir la categoria de cada línia, $group per calcular ingressos totals i unitats venudes per categoria, i $sort descendent per ingressos.
4.2 Top 5 clients per facturació. Pipeline que agrupa les comandes completades per client_id, suma el total, fa $lookup amb clients per obtenir el nom, i retorna els 5 clients amb més facturació acumulada.
4.3 Resum mensual de vendes. Pipeline que agrupa les comandes per any i mes ($year, $month sobre el camp data), calculant nombre de comandes i import total per mes, ordenat cronològicament.
4.4 Anàlisi amb $facet. Un sol pipeline que retorni en un sol document: estadístiques generals (total de comandes, import mitjà), distribució de comandes per país d'enviament i el top 3 de productes més venuts (per unitats).
Per a cadascun dels 4 pipelines, anota a l'informe quina pregunta de negoci respon i adjunta una captura del resultat.
Part 5 — Índexs i mesura del rendiment (1,5 hores)
Escriu a scripts/04_indexos.js el procediment següent (consulta Índexs i rendiment):
- Executa
db.comandes.find({ client_id: "CLI-001", estat: "completat" }).explain("executionStats")abans de crear cap índex. Anotastage,totalDocsExamined,nReturnediexecutionTimeMillis. - Crea l'índex compost que consideris més adequat per a aquesta query, seguint la regla ESR (Equality, Sort, Range).
- Torna a executar
explain("executionStats")i compara les mètriques abans/després. Adjunta totes dues captures a l'informe. - Crea un índex de text sobre el camp
nomdeproductes(especificadefault_language: "spanish") i prova una cerca amb$text: { $search: ... }. - Crea un índex sobre el camp
tags(multikey, automàtic en indexar un array) i comprova ambexplain()que una queryfind({ tags: "..." })ara fa servirIXSCANen lloc deCOLLSCAN. - Llista tots els índexs creats a
comandesiproductesambgetIndexes()i inclou la sortida a l'informe.
L'índex no sempre és la solució
Si en crear un índex explain() segueix mostrant COLLSCAN, revisa que l'ordre dels camps de l'índex compost respecta la prefix rule i que el camp té prou cardinalitat per ser útil (consulta la secció de cardinalitat i selectivitat d'Índexs i rendiment).
Lliurament
Puja al Campus Virtual un fitxer .zip anomenat PR507403_cognom_nom.zip amb l'estructura del directori pr507403-nom_cognom/ completa:
| Fitxer / carpeta | Contingut |
|---|---|
docker-compose.yml |
Definició dels serveis MongoDB i Mongo Express |
scripts/01_carrega_dades.js |
Creació de la BD i càrrega de productes, clients i comandes |
scripts/02_crud_queries.js |
Les 10 operacions CRUD i queries de la Part 3, comentades |
scripts/03_aggregation.js |
Els 4 pipelines de la Part 4, comentats |
scripts/04_indexos.js |
Creació d'índexs i comandes explain() de la Part 5 |
informe/informe_pr507403.md |
Justificació de l'esquema, captures d'explain(), taula CRUD↔SQL, resultats dels pipelines, respostes a les preguntes de reflexió |
Estructura recomanada de l'informe:
- Portada (nom, grup, data).
- Disseny de l'esquema: justificació embedding/referencing i anti-patró identificat (Part 2).
- CRUD i queries: taula d'equivalència amb SQL (Part 3).
- Aggregation Pipeline: pregunta de negoci i resultat de cada pipeline (Part 4).
- Índexs: captures d'
explain()abans/després i llistat d'índexs (Part 5). - Preguntes de reflexió final.
Sobre l'ús d'IA generativa
Pots usar IA generativa per resoldre dubtes puntuals de sintaxi, però els scripts i l'informe han de reflectir la teva pròpia comprensió del disseny i les decisions preses. El professorat pot convocar una defensa oral per verificar la comprensió del codi lliurat.
Data límit de lliurament: consulta el calendari del Campus Virtual.
Consulta la Rúbrica PR507403 per als criteris detallats d'avaluació.
Preguntes de reflexió final
Un cop completada la pràctica, reflexiona breument sobre:
- Si Sapa-Shop hagués de créixer fins als 50 milions de comandes anuals descrits al Bloc 1, quin canvi de disseny (sharding, replica set, revisió de l'embedding) consideraries prioritari?
- Quina diferència pràctica has notat entre escriure una consulta analítica amb
find()i fer-ho amb l'Aggregation Pipeline? En quin momentfind()ja no és suficient? - Després de mesurar l'impacte real d'un índex amb
explain(), com canviaria el teu criteri a l'hora de decidir si val la pena crear un índex nou en un projecte real?
Inclou les respostes a les conclusions de l'informe (3-5 línies per pregunta).
Pràctica PR507403 | Mòdul M5074 Sistemes de Big Data | Institut Sa Palomera (Blanes) | Curs CEIABD 2026-2027