Jakarta NoSQL (MongoDB) en Quarkus: Bases de Datos NoSQL con Dev Services
Introducción
Jakarta NoSQL proporciona una API estándar para trabajar con bases de datos NoSQL. En Quarkus, MongoDB está completamente soportado a través de Panache MongoDB, y Dev Services hace que trabajar con MongoDB sea extremadamente simple iniciando automáticamente un contenedor.
¿Qué es NoSQL?
NoSQL (Not Only SQL) se refiere a bases de datos que no usan el modelo relacional tradicional. MongoDB es una base de datos de documentos que almacena datos en formato BSON (Binary JSON), permitiendo estructuras flexibles y complejas.
Dev Services: La Magia de Quarkus
Dev Services es una característica de Quarkus que inicia automáticamente servicios necesarios (como MongoDB) en contenedores Docker durante el desarrollo. Esto significa:
✅ No necesitas instalar MongoDB manualmente
✅ No necesitas configurar conexiones
✅ Solo necesitas Docker instalado
✅ Quarkus lo hace todo automáticamente
# application.properties
quarkus.mongodb.devservices.enabled=true
Cuando ejecutas mvn quarkus:dev, verás:
Dev Services for MongoDB started.
Panache MongoDB
Panache MongoDB proporciona dos patrones similares a Panache para SQL:
Active Record Pattern
@MongoEntity(collection = "heroes")
public class HeroMongo extends PanacheMongoEntity {
public String name;
public Integer powerLevel;
public List<String> abilities = new ArrayList<>();
// Métodos de instancia
public void activate() {
this.isActive = true;
this.update();
}
// Métodos estáticos
public static List<HeroMongo> findPowerful(int minLevel) {
return find("powerLevel >= ?1", minLevel).list();
}
}
Repository Pattern
@ApplicationScoped
public class HeroMongoRepository implements PanacheMongoRepository<HeroMongo> {
public List<HeroMongo> findPowerful(int minPowerLevel) {
return find("powerLevel >= ?1", minPowerLevel).list();
}
}
Características Específicas de MongoDB
1. Documentos Anidados
MongoDB permite documentos dentro de documentos:
@MongoEntity(collection = "heroes")
public class HeroMongo extends PanacheMongoEntity {
public Location location; // Documento anidado
public static class Location {
public String city;
public String planet;
public Coordinates coordinates; // Anidado dentro de anidado
public static class Coordinates {
public Double latitude;
public Double longitude;
}
}
}
2. Arrays de Valores
public class HeroMongo extends PanacheMongoEntity {
public List<String> abilities = new ArrayList<>(); // Array de strings
}
3. Arrays de Documentos
public class HeroMongo extends PanacheMongoEntity {
public List<Mission> missions = new ArrayList<>(); // Array de documentos
public static class Mission {
public String title;
public String description;
public String status;
}
}
4. Queries en Documentos Anidados
// Buscar por ciudad
public List<HeroMongo> findByCity(String city) {
return find("location.city", city).list();
}
// Buscar por coordenadas anidadas
public List<HeroMongo> findByLatitude(double lat) {
return find("location.coordinates.latitude", lat).list();
}
5. Queries en Arrays
// Buscar héroes que tengan una habilidad específica
public List<HeroMongo> findByAbility(String ability) {
return find("abilities", ability).list();
}
// Buscar héroes con misiones pendientes
public List<HeroMongo> findWithPendingMissions() {
return find("missions.status", "PENDING").list();
}
ObjectId vs Long
MongoDB usa ObjectId como identificador en lugar de Long:
@MongoEntity(collection = "heroes")
public class HeroMongo extends PanacheMongoEntity {
// El campo 'id' es de tipo ObjectId (hereda de PanacheMongoEntity)
// No necesitas declararlo
}
// En los endpoints REST
@GET
@Path("/heroes/{id}")
public Response getHero(@PathParam("id") String id) {
ObjectId objectId = new ObjectId(id); // Convertir String a ObjectId
HeroMongo hero = HeroMongo.findById(objectId);
return Response.ok(hero).build();
}
Operaciones Comunes
Crear
HeroMongo hero = new HeroMongo("Superman", "Super strength", 95);
hero.addAbility("Flight");
hero.addAbility("Heat vision");
hero.persist(); // Active Record
Buscar
// Por ID
HeroMongo hero = HeroMongo.findById(objectId);
// Por campo
List<HeroMongo> heroes = HeroMongo.find("name", "Superman").list();
// Con condición
List<HeroMongo> powerful = HeroMongo.find("powerLevel >= ?1", 80).list();
Actualizar
HeroMongo hero = HeroMongo.findById(objectId);
hero.powerLevel = 98;
hero.addAbility("New ability");
hero.update(); // Active Record
Eliminar
HeroMongo.deleteById(objectId);
hero.delete(); // Active Record
Ejemplo Completo: Estructura Compleja
HeroMongo superman = new HeroMongo("Superman", "Super strength", 95);
superman.addAbility("Flight");
superman.addAbility("Heat vision");
// Ubicación anidada
HeroMongo.Location location = new HeroMongo.Location();
location.city = "Metropolis";
location.planet = "Earth";
HeroMongo.Location.Coordinates coords = new HeroMongo.Location.Coordinates();
coords.latitude = 40.7128;
coords.longitude = -74.0060;
location.coordinates = coords;
superman.location = location;
// Misiones anidadas
HeroMongo.Mission mission = new HeroMongo.Mission();
mission.title = "Salvar Metropolis";
mission.description = "Detener a Lex Luthor";
mission.status = "COMPLETED";
superman.addMission(mission);
superman.persist();
Ventajas de MongoDB
Flexibilidad: Esquema flexible, documentos pueden variar
Estructuras Complejas: Documentos anidados y arrays nativos
Performance: Mejor para lectura de documentos completos
Escalabilidad: Escala horizontalmente fácilmente
Comparación: SQL vs NoSQL
| Característica | SQL (JPA) | NoSQL (MongoDB) |
| Estructura | Tablas fijas | Documentos flexibles |
| Relaciones | JOINs explícitos | Documentos anidados |
| Arrays | Tablas separadas | Arrays nativos |
| Esquema | Fijo | Flexible |
| Queries | SQL/JPQL | Queries de documentos |
| Escalabilidad | Vertical | Horizontal |
Cuándo Usar MongoDB
✅ Datos con estructura variable
✅ Documentos complejos con anidación
✅ Escalabilidad horizontal importante
✅ Lecturas frecuentes de documentos completos
✅ Datos que no requieren transacciones complejas
Dev Services en Detalle
Dev Services:
Detecta si MongoDB está corriendo localmente
Si no está, inicia un contenedor Docker automáticamente
Configura la conexión automáticamente
Limpia el contenedor al detener la aplicación
Solo funciona en modo desarrollo. Para producción, configura MongoDB manualmente.
Ejemplo Completo
Nuestro demo muestra:
Panache MongoDB con Active Record y Repository patterns
Documentos anidados (location, secretBase)
Arrays de valores (abilities, allies)
Arrays de documentos anidados (missions)
Queries en estructuras complejas
Dev Services para MongoDB automático
Operaciones CRUD completas
Conclusión
MongoDB con Panache MongoDB en Quarkus proporciona acceso simple a bases de datos NoSQL. Dev Services elimina completamente la configuración manual, mientras que Panache MongoDB simplifica el código. La flexibilidad de MongoDB es perfecta para datos con estructuras complejas y variables.




