UC00664

Bases de Dados NoSQL

MongoDB, Redis, Elasticsearch

Curso profissional · 50h · BDs modernas

Plano

  1. SQL vs NoSQL — quando usar
  2. Tipos de NoSQL
  3. MongoDB (document)
  4. Redis (key-value)
  5. Elasticsearch (search)
  6. Modelagem em document DBs
  7. Performance e escala
  8. Backup e segurança

Bloco 1 · SQL vs NoSQL

SQL (relacional)

  • MySQL, PostgreSQL, SQLite, SQL Server, Oracle.
  • Tabelas com schemas rígidos.
  • Relações via JOINs.
  • ACID (Atomicity, Consistency, Isolation, Durability).
  • Mature, bem entendido, suporte excelente.
SELECT u.name, COUNT(o.id) 
FROM users u 
LEFT JOIN orders o ON o.user_id = u.id 
GROUP BY u.id;

NoSQL — alternativa

  • Schemas flexíveis ou ausentes.
  • Optimizadas para casos específicos (escala, latência, queries).
  • Diferentes paradigmas: document, key-value, column, graph, search.
  • BASE (Basically Available, Soft state, Eventually consistent) em vez de ACID estrito.

Quando NoSQL faz sentido

✅ Schema flexível (user-generated content, IoT).
✅ Escala horizontal (milhões de utilizadores).
✅ High throughput (cache, sessions).
✅ Full-text search.
✅ Real-time (chats, notifications).

❌ Transações complexas multi-row.
❌ Joins frequentes.
❌ Reporting/BI tradicional.

Bloco 2 · Tipos de NoSQL

Document stores

  • MongoDB — JSON-like, mais popular.
  • CouchDB — sync-friendly.
  • Firebase Firestore — real-time, cloud.

Cada record = "document" (JSON). Sem schema rígido.

{
  "_id": "user123",
  "name": "Ana",
  "email": "ana@x.pt",
  "orders": [{"id": 1, "total": 50}, {"id": 2, "total": 30}]
}

Key-value

  • Redis — in-memory, rápido.
  • Memcached.
  • DynamoDB (AWS, parte).

Chave → valor (string, número, hash, lista, set).

SET session:abc123 "{user: 'Ana', exp: ...}"
GET session:abc123

Wide-column

  • Cassandra.
  • HBase.
  • ScyllaDB.

Escalam imensamente (PB+). Usados em logging, IoT, fraud detection.

Graph

  • Neo4j.
  • ArangoDB.

Nodes + relationships. Ideal para social networks, recommendations, fraud detection.

MATCH (u:User)-[:FRIEND]->(f:User)
WHERE u.name = "Ana"
RETURN f.name
  • Elasticsearch (e Open Search).
  • Algolia (SaaS).
  • Meilisearch.

Optimizados para full-text search, aggregations, faceting.

Bloco 3 · MongoDB

Setup

# Docker (mais fácil)
docker run -d -p 27017:27017 --name mongo mongo:7

# Ou MongoDB Atlas (cloud free tier)
# https://www.mongodb.com/cloud/atlas

Cliente: MongoDB Compass (GUI), mongosh (CLI), drivers Python/Node/Java.

Conceitos

MongoDB instance
└── Database (ex: "loja")
    └── Collection (ex: "products")
        └── Document (JSON-like)
  • Database = "BD".
  • Collection = "tabela" (sem schema rígido).
  • Document = "linha" (BSON, similar a JSON).

Operações CRUD

// Connect
use loja

// Insert
db.products.insertOne({
  name: "Caneta",
  price: 1.50,
  stock: 100
});

// Insert many
db.products.insertMany([
  {name: "Caderno", price: 5.00, stock: 50},
  {name: "Mochila", price: 35.00, stock: 20}
]);

// Find all
db.products.find();

// Find one
db.products.findOne({name: "Caneta"});

Queries

// Filtros
db.products.find({price: {$gt: 10}});       // price > 10
db.products.find({stock: {$lte: 50}});      // stock <= 50

// AND
db.products.find({
  price: {$gt: 10}, 
  stock: {$lt: 100}
});

// OR
db.products.find({
  $or: [{price: {$lt: 5}}, {stock: 0}]
});

// In
db.products.find({name: {$in: ["Caneta", "Caderno"]}});

// Regex
db.products.find({name: /^Ca/});

// Projection (só campos)
db.products.find({}, {name: 1, price: 1});

// Sort + limit
db.products.find().sort({price: -1}).limit(10);

Update e Delete

// Update one
db.products.updateOne(
  {name: "Caneta"},
  {$set: {price: 1.80}}
);

// Update many
db.products.updateMany(
  {stock: 0},
  {$set: {discontinued: true}}
);

// Operadores: $set, $inc, $push, $pull
db.products.updateOne(
  {_id: ObjectId("...")},
  {$inc: {stock: -1}}
);

// Delete
db.products.deleteOne({name: "Velho"});
db.products.deleteMany({stock: 0});

Aggregation pipeline

// Total vendas por categoria
db.orders.aggregate([
  {$match: {date: {$gte: new Date("2026-01-01")}}},
  {$group: {
    _id: "$category",
    total: {$sum: "$amount"},
    count: {$sum: 1}
  }},
  {$sort: {total: -1}},
  {$limit: 10}
]);

Pipeline = lista de stages. Equivalente NoSQL ao GROUP BY + WHERE + ORDER BY.

Python driver — pymongo

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db = client.loja
products = db.products

# Insert
products.insert_one({"name": "Caneta", "price": 1.50})

# Find
for p in products.find({"price": {"$gt": 5}}):
    print(p["name"], p["price"])

# Aggregate
result = products.aggregate([
    {"$group": {"_id": "$category", "total": {"$sum": "$price"}}}
])

Bloco 4 · Redis

Para que serve

  • Cache (resultados de queries lentas).
  • Sessions (login state).
  • Rate limiting.
  • Pub/sub (real-time).
  • Queues (background jobs).
  • Leaderboards (sorted sets).

In-memory = microssegundos de latência.

Setup

docker run -d -p 6379:6379 redis:7

# CLI
redis-cli

Tipos de dados

# String
SET nome "Ana"
GET nome
EXPIRE nome 60        # TTL em segundos

# Number (string que parece int)
INCR contador        # +1
INCRBY contador 5

# Hash (objecto)
HSET user:1 name "Ana" age 25
HGET user:1 name
HGETALL user:1

# List (queue/stack)
LPUSH queue "task1"
RPOP queue

# Set (únicos, sem ordem)
SADD tags "python" "web"
SMEMBERS tags

# Sorted set (score → member)
ZADD leaderboard 100 "Ana" 200 "Bruno"
ZRANGE leaderboard 0 -1 WITHSCORES

Cache pattern

import redis
import json

r = redis.Redis(host='localhost', port=6379)

def get_user(id):
    key = f"user:{id}"
    
    # Try cache
    cached = r.get(key)
    if cached:
        return json.loads(cached)
    
    # Miss → fetch from DB
    user = fetch_user_from_db(id)
    
    # Cache for 1h
    r.setex(key, 3600, json.dumps(user))
    
    return user

Bloco 5 · Elasticsearch

Para que serve

  • Full-text search (Google-like).
  • Logging (com Logstash + Kibana = ELK stack).
  • Analytics.
  • APM (application monitoring).

Setup

docker run -d -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  elasticsearch:8.12.0
curl http://localhost:9200
# {"cluster_name": ...}

Indexar e procurar

# Index document
curl -X POST "localhost:9200/products/_doc" \
  -H 'Content-Type: application/json' \
  -d '{"name": "Caneta azul", "price": 1.50}'

# Full-text search
curl -X GET "localhost:9200/products/_search" \
  -H 'Content-Type: application/json' \
  -d '{"query": {"match": {"name": "azul"}}}'

Retorna scored results — mais relevantes primeiro.

Bloco 6 · Modelagem

SQL vs Document

SQL (normalizado):

users
  id, name, email

orders
  id, user_id, total, date

MongoDB (denormalizado):

{
  "name": "Ana",
  "email": "ana@x.pt",
  "orders": [
    {"id": 1, "total": 50, "date": "2026-01-15"},
    {"id": 2, "total": 30, "date": "2026-02-01"}
  ]
}

Embed vs Reference

Embed (data dentro):

  • Pros: 1 query, atomicidade.
  • Cons: doc cresce, duplicação.
  • Use quando: 1:1 ou 1:N pequeno, frequentemente lido junto.

Reference (ID linkado):

  • Pros: sem duplicação, doc pequeno.
  • Cons: precisa segunda query.
  • Use quando: N:M, dados independentes.
// Embed
{
  "post": "...",
  "comments": [{"text": "...", "author": "..."}]
}

// Reference
{
  "post": "...",
  "comment_ids": ["c1", "c2"]
}

Trade-offs

  • Sem JOINs nativos: ou denormalizas (embed) ou fazes 2 queries.
  • Schema flexível = liberdade mas também caos.
  • Eventual consistency: replicação tem delay.
  • Sharding: escala horizontal mas adiciona complexidade.

Bloco 7 · Performance

Indexes

// MongoDB
db.products.createIndex({name: 1});         // ascending
db.products.createIndex({price: 1, stock: -1}); // composto

// Verificar uso
db.products.find({name: "Caneta"}).explain("executionStats");

Sem index, find = scan da collection inteira.

Sharding e replication

  • Replica set (MongoDB): primary + secondaries (high availability).
  • Sharding: dados divididos por chave entre nodes (scale horizontal).
  • Redis Cluster: hash slots em vários nodes.

Setup complexo — normalmente cloud-managed (Atlas, ElastiCache).

Bloco 8 · Backup e segurança

Backup MongoDB

# Backup
mongodump --uri="mongodb://localhost:27017" --out=/backup

# Restore
mongorestore --uri="mongodb://localhost:27017" /backup

Atlas: backups automáticos integrados.

Segurança

  • Autenticação: utilizadores com roles.
  • TLS: connections encriptadas.
  • Network: firewall, VPC.
  • Field-level encryption (MongoDB enterprise).
  • GDPR: anonimização, right to be forgotten.
mongosh --username admin --password ... --authenticationDatabase admin

UC00664 · resumo

  • NoSQL = alternativa a SQL para casos específicos.
  • Document (MongoDB) = JSON-like, flexível.
  • Key-value (Redis) = ultra-rápido, in-memory.
  • Search (Elasticsearch) = full-text + analytics.
  • MongoDB CRUD + aggregation pipeline.
  • Modelagem: embed vs reference (trade-offs).
  • Indexes essenciais para performance.
  • Sharding + replication para escala.
  • Cloud-managed (Atlas, ElastiCache) é norma.