Skip to main content

Jakarta NoSQL con MongoDB perspectivas

 Jakarta NoSQL con MongoDB perspectivas

Hace unos años conversaba con un gran amigo Otavio Santa, acerca de bases de datos NoSQL.

Es admirable el trabajo que lleva adelante Otavio y otros desarrolladores en la especificación Jakarta NoSQL.

La definición oficial en el sitio de Jakarta:

"Jakarta NoSQL is a Java API standard that streamlines the integration of Java applications with NoSQL databases. It defines a set of APIs and provides a standard implementation for most NoSQL databases. The goal is to create the specification in Jakarta EE to help Jakarta EE developers create enterprise-grade applications using Java® and NoSQL technologies. It helps them create scalable applications while maintaining low coupling with the underlying NoSQL technology."


Si leemos un poco la documentación oficial nos encontraremos que se define mediante dos capas:

  • Communication Layer: Contiene 4 módulos uno para cada tipo de bases de datos NoSQL. Es como  JDBC para bases de datos relacionales.
  • Mapping Layer: Esta capa utiliza CDI, Bean Validaton, anotaciones para ofrecer sencillez a los desarrolladores, Se puede comparar con JPA.

Su uso es muy sencillo, definimos entidades de manera simple, y mediante interfaces usando el patrón Repository tenemos una gran funcionalidad con poco esfuerzo.

Hasta el momento de escribir este articulo es importante mencionar que no se soporta agregaciones por lo cual no podemos utilizar referencias entre documentos, tenemos que definir un modelo de datos optimizado generalmente usando documentos embebidos para el caso de MongoDB. 

Su flexibilidad e integración con Microprofile es muy sencilla. Solamente agregamos al archivo micrroprofile-config, los atributos que indican el tipo de base de datos y los parámetros de conexión.


Definimos  nuestras entidades: Persona.java , Pais.java, Dirección.java, que representa la colección Persona y Pais en MongoDB. Lo hacemos de esta manera a modo de ejemplo:
Ejemplo A:



Para el ejemplo definimos Pais como un entity pero le agregamos el atributo @Id




Crear la interface Repository para Persona

public interface PersonaRepository extends Repository<Persona, String> {

    Stream<Persona> findAll();

    Page<Persona> findAll(Pagination pagination);


      //Busca en el documento embebido
    @Query("select * from Persona where pais.code = @code")
    Stream<Persona> findByPaisIn(@Param("code") String code);

  Stream<Persona> findByName(String name);

}


Ahora creamos la interface Repository para Pais

Observe que estamos creando una consulta buscando en el documento embebido mediante pais.code



Crear el controlller utilizando Eclipse Microprofile


@ApplicationScoped
@Path("pais")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PaisController {

    private static final Supplier<WebApplicationException> NOT_FOUND =
            () -> new WebApplicationException(Response.Status.NOT_FOUND);

    @Inject
    private PaisRepository repository;

    @GET
    public List<Pais> findAll() {
        return repository.findAll()
                .collect(toList());
    }

    @GET
    @Path("/{id}")
    public Pais findById(@PathParam("id") String id) {
        return repository.findById(id).orElseThrow(NOT_FOUND);
    }

    
    @GET
    @Path("search/{name}")
    public List<Pais> findByYounger(@PathParam("name") String name) {
        return repository.findByName(name)
                .collect(toList());
    }

    @POST
    public void save(Pais hero) {
        repository.save(hero);
    }

    @PUT
    @Path("/{id}")
    public void update(@PathParam("id") String id, Pais hero) {
        repository.save(hero);
    }

    @Path("/{id}")
    @DELETE
    public void delete(@PathParam("id") String name) {
        repository.deleteById(name);
    }
}


Ahora crearmos el controller PersonaController.java

@ApplicationScoped
@Path("persona")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PersonaController {

    private static final Supplier<WebApplicationException> NOT_FOUND =
            () -> new WebApplicationException(Response.Status.NOT_FOUND);

    @Inject
    private PersonaRepository repository;

    @GET
    public List<Persona> findAll() {
        return repository.findAll()
                .collect(toList());
    }

    @GET
    @Path("/{id}")
    public Persona findById(@PathParam("id") String id) {
        return repository.findById(id).orElseThrow(NOT_FOUND);
    }

    @GET
    @Path("searchpais/{code}")
    public List<Persona> findByPaisIn(@PathParam("code") String  code) {
     
       return repository.findByPaisIn(code)
                .collect(toList());
    }
    

    
    @POST
    public void save(Persona hero) {
        repository.save(hero);
    }

    @PUT
    @Path("/{id}")
    public void update(@PathParam("id") String id, Persona hero) {
        repository.save(hero);
    }

    @Path("/{id}")
    @DELETE
    public void delete(@PathParam("id") String name) {
        repository.deleteById(name);
    }
}


Insertamos algunos documentos en la colección Pais

curl -H "Content-Type: application/json" -X POST -d '{ "code": "pa","name": "Panama"}' http://localhost:8080/microjakartanosql/api/pais/
curl -H "Content-Type: application/json" -X POST -d '{ "code": "eu","name": "Estados Unidos"}' http://localhost:8080/microjakartanosql/api/pais/
curl -H "Content-Type: application/json" -X POST -d '{ "code": "cu","name": "Cuba"}' http://localhost:8080/microjakartanosql/api/pais/




Insertamos documentos en la colección Persona


curl -H "Content-Type: application/json" -X POST -d '{"id": "7","name": "Aristides","pais":{ "code": "pa","name": "Panama"},"direccion":{ "street": "Calle 1","city": "Los Santos"}}' http://localhost:8080/microjakartanosql/api/persona/
curl -H "Content-Type: application/json" -X POST -d '{"id": "8","name": "Ana","pais":{ "code": "cu","name": "Cuba"},"direccion":{ "street": "La habana","city": "La habana"}}' http://localhost:8080/microjakartanosql/api/persona/

Podemos observar una situación interesante 

La colección Persona en MongoDB  no genera el documento embebido pais y el campo code, es reemplazado automáticamente por _id.


. Esto ocurre porque en nuestra entidad Pais, definimos el atributo 


y queríamos que se almacenar el atributo code.
Que hicimos mal o en que estamos fallando, en primer lugar si le ocurre esta situación indica que no hemos analizado bien el modelo de datos que queremos usar. Habia comentado inicialmente que Jakarta NoSQL no soporta aun documentos referenciados. Por la tanto podemos observar que dirección se almaceno correctamente los atributos street, city.
En la definición de la entidad
No contamos con ninguna columna definida con el atributo @Id

Por lo tanto si eliminamos la anotación @Id de la entidad Pais.java

Y eliminamos los documentos de nuestra colección  Persona en MongoDB y detenemos nuesto microservicio y lo volvemos a ejecutar.

curl -H "Content-Type: application/json" -X POST -d '{"id": "7","name": "Aristides","pais":{ "code": "pa","name": "Panama"},"direccion":{ "street": "Calle 1","city": "Los Santos"}}' http://localhost:8080/microjakartanosql/api/persona/
curl -H "Content-Type: application/json" -X POST -d '{"id": "8","name": "Ana","pais":{ "code": "cu","name": "Cuba"},"direccion":{ "street": "La habana","city": "La habana"}}' http://localhost:8080/microjakartanosql/api/persona/

Podemos observar que se almacena correctamente


Como eliminamos el  @Id del entity Pais, no podremos insertar los registros

curl -H "Content-Type: application/json" -X POST -d '{"id": "7","name": "Aristides","pais":{ "code": "pa","name": "Panama"},"direccion":{ "street": "Calle 1","city": "Los Santos"}}' http://localhost:8080/microjakartanosql/api/persona/
curl -H "Content-Type: application/json" -X POST -d '{"id": "8","name": "Ana","pais":{ "code": "cu","name": "Cuba"},"direccion":{ "street": "La habana","city": "La habana"}}' http://localhost:8080/microjakartanosql/api/persona/


ya que nos enviara el error






Indicando que solo usaremos una colección Persona, y tanto Direccion como Pais, serán embebidos


Por la tanto son los cambios importantes que debemos considerar al trabajar con bases de datos NoSQL y con las diversas implementaciones.
Muchas veces tenemos que redefinir adecuadamente para aprovechar el potencial 


Comments

Popular posts from this blog

Tutorial básico de aplicaciones Web con NetBeans parte 1

NetBeans ofrece un excelente soporte para el desarrollo de aplicaciones Web, en esta ocasión lo haremos utilizando el Framework Java Server Faces 2.0. En el Menu Seleccionamos Nuevo->Proyecto y luego en Categorias Java Web y en tipo de Proyectos Web  Application indicamos el nombre del proyecto Seleccinamos el servidor Web, usamos GlassFish ya que este soporta EJB3.0 y JSF 2.0 Framework Java Server Faces El IDE genera el esquelto del proyecto Web Pages   almacenamos las paginas .html, xhtml, jsf, los archivos de recursos, los scripts .js, imagenes Source Packages    Son las clases Java  Test Packages    Son las clases que usamos para los Test Libraries     Tenemos las bibliotecas de Java y GlassFish necesarias para ejecutar la aplicación Web. Test Libraries     Están las bibliotecas usadas para los test  Configuration Files    Archivos de configuración de la aplicación. Ejecutamos la...

Incrementar Memoria NetBeans

Algunas veces necesitamos incrementar la memoria para un mejor rendimiento. http://www.netbeans.org/community/releases/55/uml-download.html Este es un ejemplo para UML. Descripción en ingles. Increasing Memory Settings (applicable to all builds) The default memory settings for NetBeans should be increased for UML projects. If you have the available memory, Locate your NetBeans installation directory ($install_dir). This can be found by starting up NetBeans and selecting Help -> About then select the Detail tab. Edit the $install_dir/etc/netbeans.conf file. Find the line defining netbeans_default_options . Increase the maximum memory attribute to -J-Xmx512m. If you experience heap overflows while working with larger files, you should increase this value further.

Cambiando el estado de un checkbox

Cambiando el Estado de un CheckBox Algunas veces deseamos controlar el estado de un checkbox o cambiarlo segùn determinadas condiciones. Pasos: 1. Creamos un proyecto Web. 2. En el diseñador agregamos un checkbox y dos botones. * Dar click derecho en el checkbox y luego seleccionar Add Binding Attribute, para agregar los atributos al checkbox, de manera que los podamos usar en nuestro código. Generando automáticamente private Checkbox checkbox1 = new Checkbox(); public Checkbox getCheckbox1() { return checkbox1; } public void setCheckbox1(Checkbox c) { this.checkbox1 = c; } 3.Damos click derecho en el botón Habilitar, y seleccionamos Edit Action Event Handler. A continuación, agregamos el código: this.checkbox1.setSelected(true);, el método setSelected con valor true, marca el checkbox como seleccionado, y un valor de false, quita la marca. public String button1_action() { // TODO: Process the action. Return value is a navigation // ...