MongoDB en Java y Tomcat.
Tomcat posee unos jar que permiten implementar las librerías para ser usadas en el manejo de la base de datos.
Al momento de este artículos estamos en la versión| 4.3.1 con los siguientes archivos para implementarlos que se pueden descargados de https://jar-download.com/artifacts/org.mongodb
1. bson-4.3.1.jar
2. mongodb-driver-core-4.3.1.jar
3. mongodb-driver-sync-4.3.1.jar
Y que como es tradicional en tomcat deben ser colocados en la carpeta /lib de tomcat.
De forma general funciona bien, el problema que hay que aunque la información para el uso de MongoDB es en general amplia, bien presentada y llena de casos de uso y ejemplo, no ocurre lo mismo cuando se trata de hacer uso de la misma bajo java, en general las variables, funciones y procedimientos son simétricos en cuanto a su funcionalidad, pero la la verdad es la aplicación de estos en en java no es cosa trivial, tiene una curva de aprendiza dura, no es por así decirlo precisamente intuitivo.
Algo que parece muy interesante en cuanto del uso de los comandos MongoDB , es que muchos autores se han gasto su tiempo documento y haciendo muy buenos ejemplo del contrates SQL vs MongoDB, es decir muestran los equivalentes, eso sin duda ayuda mucho a comprender el entono nuevo.
En este enlace se tiene una buena referencia a lo que acabo de enunciar.
https://www.gpsos.es/2020/03/consultas-select-en-mongodb-aprende-jugando/
Por ejemplo:
SELECT * FROM clientes → db.coleccion.find( { filtro } )
SELECT * FROM clientes WHERE nombre = "Linda" → db.clientes.find( { nombre: "Linda" } )
Pero como digo una cosa es entender MongoDB y otra muy distinta tratar de aplicarlo en Java.
Cuando un entra en contacto con el entorno MongoDB, y su aplicación Java en verdad parece otra cosa, nada que ver salvo algunos principios muy básicos.
En cuanto los procesos de Grabación, Borrado y Actualización en si mismo no es mucha la complicación y suele trabajar de forma sencilla en base a un grupo de comando mas o menos simples o por lo menos una vez efectuado de forma exitosa , en adelante es replicarlos cada vez que se necesite.
Que lucen mas o menos similar a esto con pocos cambios en generales
CREAR
MongoCollection<Document> collection = mgDB.getCollection("TERCEROS") ;
Document data = new Document() ;
data.append("terceroId" ,terceros.getTerceroId()) ;
data.append("terceroNombre" ,terceros.getTerceroNombre()) ;
data.append("terceroTelefono" ,terceros.getTerceroTelefono()) ;
data.append("terceroDireccion" ,terceros.getTerceroDireccion()) ;
data.append("terceroEmail" ,terceros.getTerceroEmail()) ;
;
data.append("timeStamp" ,Sos.TimeStamp()) ;
try
{
collection.insertOne(data) ;
return (true) ;
}
catch(Exception e)
{
System.out.println("Error Terceros Crear : " + e.toString()) ;
e.printStackTrace(System.out) ;
return (false) ;
}
EDITAR
MongoCollection<Document> collection = mgDB.getCollection("TERCEROS") ;
Document data = new Document() ;
Document mgUpdate = new Document() ;
Document mgQuery = new Document() ;
ArrayList<Document> myWhereO = new ArrayList<Document>() ;
ArrayList<Document> myWhereY = new ArrayList<Document>() ;
myWhereO.add(new Document("registro",terceros.getTerceroRegistro())) ;
mgQuery.append("$or" ,myWhereO) ;
mgQuery.append("$and",myWhereY) ;
data.append("terceroId" , terceros.getTerceroId()) ;
data.append("terceroCodigo" , terceros.getTerceroId()) ;
data.append("terceroNombre" , terceros.getTerceroNombre()) ;
data.append("terceroTelefono" , terceros.getTerceroTelefono()) ;
data.append("terceroDireccion" , terceros.getTerceroDireccion()) ;
data.append("terceroEmail" , terceros.getTerceroEmail()) ;
mgUpdate.append("$set",data) ;
try
{
UpdateResult resultado = collection.updateMany(mgQuery,mgUpdate) ;
long filasAfectadas = resultado.getModifiedCount() ;
if (filasAfectadas > 0)
{
return(true) ;
}
else
{
return(false) ;
}
}
catch(Exception e)
{
System.out.println("Error Terceros Editar : " + e.toString()) ;
e.printStackTrace(System.out) ;
return (false) ;
}
BORRAR
MongoCollection<Document> collection = mgDB.getCollection("TERCEROS") ;
Document mgQuery = new Document() ;
ArrayList<Document> myWhereO = new ArrayList<Document>() ;
ArrayList<Document> myWhereY = new ArrayList<Document>() ;
myWhereO.add(new Document("registro",terceros.getTerceroRegistro())) ;
mgQuery.append("$or" ,myWhereO) ;
mgQuery.append("$and",myWhereY) ;
try
{
DeleteResult resultado = collection.deleteMany(mgQuery) ;
long filasAfectadas = resultado.getDeletedCount() ;
if (filasAfectadas > 0)
{
return(true) ;
}
else
}
}
catch(Exception e)
{
System.out.println("Error Terceros Borrar : " + e.toString()) ;
e.printStackTrace(System.out) ;
return (false) ;
}
}
Se puede ver que salvo las instrucciones resaltas la mayoría son instrucciones , diríamos de tramite y generalmente iguales, lo único para tener en cuenta es que esta los procedimientos para editar y borrar pueden eventualmente necesitar el uso de algún tipo filtro, que usualmente no suelen se demasiados complejos (digo “general”) limitando a uso de condicionales relativamente simples de agrupaciones AND y OR., como se puede verificar el uso de grupos de AND y OR y para otros muchos usos el modelo MongoDB hace uso extensivo de Vectores, Listas y Vectores y mezclas de estos conceptos.
Para los dos casos de Editar y Borrar , puede usar el concepto ArrayList , lo que da un manejo bastan limpio y simple para acomodar filtros encadenados en este tipo de sentencias, pudiendo tener tantas como se requiere, simplemente adicionando la clausas a este tipo de arreglos, pero como digo no suelen ser demaciasas, en este caso
myWhereO.add(new Document("registro",terceros.getTerceroRegistro())) ;
O sea una búsqueda por el número de registro que se pasa como parámetro para efectuar el procedimiento
Nota: Yo uso mucho este tipo de manejo o sea las actualizaciones y borrados en lazados a un registro único en a DB, ingresado al momento de la creación del documento. Esa mecánica me simplifica enormemente los desarrollos , especialmente en los manejos CRUD, puesto que La creación, edicion y borrados son siempre iguales, ajustando desde luego los nombre de las colecciones y desde luego los campos pero la mecánica es siempre igual.
Hasta aquí con un poco de atención es posible crear un programa no muy complejo siguiendo esos sencillos procesos, donde los campos de la DB obedecen a simples Bean definidos previamente.
Bueno y donde esta la complejidad?
Al parecer es seguir una receta como de cocina y así es verdad, hasta aquí, y si se quieren consultas muy, muy simples casi se puede seguir con la misma mecánica., teniendo presente unidamente que los ArrayList son arreglos de document().
CONSULTAR
TercerosDTO tercerosC = new TercerosDTO() ;
Vector< TercerosDTO > gDato = new Vector< TercerosDTO >() ;
String buscar = Sos.Lower(terceros.getTerceroBuscar()) ;
String sort = terceros.getTerceroSort() ;
int limite = 50000 ;
int offSet = 0 ;
Document data = new Document() ;
Document mgFields = new Document() ;
Document mgQuery = new Document() ;
Document mgSort = new Document() ;
Document mgRegex = new Document("$regex","(?i)" + Pattern.quote(Codec.Enc(buscar)));
ArrayList<Document> myWhereO = new ArrayList<Document>() ;
ArrayList<Document> myWhereY = new ArrayList<Document>() ;
if ("NOMBRE".equals(sort)) { mgSort.append("terceroNombre" , 1) ; }
if ("TELEFONO".equals(sort)) { mgSort.append("terceroTelefono" , 1) ; }
if ("DIRECCION".equals(sort)) { mgSort.append("terceroDireccion" , 1) ; }
if ("EMAIL".equals(sort)) { mgSort.append("terceroEmail" , 1) ; }
try
{
mgQuery.append("$or" ,myWhereO) ;
mgFields.append("_id",0) ;
MongoCursor<Document> cursor = collection.find(mgQuery).projection(mgFields).sort(mgSort).limit(limite).skip(offSet).cursor() ;
while (cursor.hasNext())
{
tercerosC = new TercerosDTO() ;
data = cursor.next() ;
data.getString("terceroNombre").indexOf(buscar) != -1 ||
data.getString("terceroTelefono").indexOf(buscar) != -1 ||
data.getString("terceroDireccion").indexOf(buscar) != -1 ||
data.getString("terceroEmail").indexOf(buscar) != -1 ||
mgFields.append("_id",0) ;
MongoCursor<Document> cursor = collection.find(mgQuery).projection(mgFields).sort(mgSort).limit(limite).skip(offSet).cursor() ;
tercerosC.setTerceroId(data.getString("terceroId")) ;
tercerosC.setTerceroNombre(data.getString("terceroNombre")) ;
tercerosC.setTerceroTelefono(data.getString("terceroTelefono")) tercerosC.setTerceroEmail(data.getString("terceroEmail")) ;
tercerosC.setTerceroTimeStamp(data.getString("timeStamp")) ;
gDato.add(tercerosC) ;
}
cursor.close() ;
return(gDato) ;
}
catch(Exception e)
{
System.out.println("Error Terceros Consultar : " + e.toString()) ;
e.printStackTrace(System.out) ;
gDato.add(tercerosC) ;
return (gDato) ;
}
En esta sencilla consulta , se le pasa un parámetro al procedimiento llamado buscar que se compara con los distintos campos de la DB para extrae los documentos que coincidan con la información, la cual almacena en un Vector que le pasa al procedimiento con la información encontrada, no hay nada nuevo allí simplemente la clausa OR esta compuesta ahora de varias posibles coincidencias y el modelo de organización (Sort), presenta la información ordenada por el campo que coincida con el LABEL del if, en este caso la clausula AND no aplica son simples OR.
Se puede ver que se asemeja a los conceptos de borrar y editar, pero find permite definir cuantos registros deseo solicitar (limit), como clasifico la información (sort), a partir del registro que empieza la consulta (offset) y que campios deseo mostrar (proyection) , en este caso los muestro todos excepto el id_ ( solo por ilustración de definición de este campo), los campos de sort (ordenamiento, si tiene un 1 es ascendente y -1 para descendente, poco mas hay que tener en cuento, y la busqueda es plana , a una variable de la colección se compara con una variable definida por un bean
Digamos por ejemplo en este caso por ejemplo
data.getString("terceroNombre").indexOf(buscar) != -1
Se pide al sistema que verifique si el contenido de la variable en el campo Nombre esta contenida en el bean buscar pasado como parámetro.
Como dije anteriormente es hacer esto de forma repetitiva hasta obtener la salida de interés., sin embargo el mundo real necesita consultas mucho mas complejas que simples compraciones de igualdad o contenido y es allí donde la cosa se pone buena, porque el modelo de consulta ya no puede llenar nuestras expectativas, y el problema con que empiezo el articulo es que es casi todo lo que hay respecto al manejo de mongoDB para java poco mas o menos.
Bueno si se requiren consultas realmente complejas esto simple y lineamiento no nos sirve, pero no es que el drive de java no lo proporciones , si que tiene soluciones a todas nuestras preguntas, pero lastimosamente no es que esten tan prolijamente ordenas, exhustivamente explicadas y llenas de ejemplos, la verdad es que no o yo lo menos no he encontrada cosas mas alla de lo trivial y sencillo.
MongoDB cuenta con un modelo para querys (consultas) y filtros altamente sofisticado llamado Aggregation, herramienta verdaderamente poderosa para computo de resultados y creación de consultas, busquedas y filtros realmente sofisticados, el problema no es que no exista y tenga muchisimos ejemplos de su uso, si los hay y están bien documentados pero no en Java, donde a mi por lo menos al principio no podía entender como funcionaba porque veía el modelo que acabo de anotar y trataba de aplicar la misma lógica, pero nada que ver , es otro mundo, otros conceptos y desde luego otro aprendizaje.
Les confieso que perdí mucho tiempo tratando de aplicar la lógica aprendida con lo anterior, incluso usando las mismas librerías, a punto estuve de renunciar a este herramienta de almacenamiento de información, pues aunque podía hacer algunas cosas sencillas y manejo de consultas simples para lo grueso del sistema no avanzaba nada, lo que me dio animo fue que encontré entre tanto buscar información para un sistema de seguridad de activos (cheques, títulos valores et que estoy desarrollando), que había una herramienta denominada BigChainDB (en MongoDB claro esta), para manejo de sistemas de alta encriptación y procesos similares a crypto monedas pero con un modelo mas funcional al de Bitcoin,Ethereum, aunque no venia al caso, me anime de nuevo a buscar una solución para poder generar consultas complejas mediante mongoDB en java y apklicar BigChainDB a mi sistema. https://www.mongodb.com/partners/bigchaindb
La solución la tenia a mano, solo que nunca se me habita ocurrido usarla para esto es el administrador gráfico de mongo, denomina Mongo Compass https://www.mongodb.com/try/download/compass
Pues si, resulta que alguien muy ingenioso pensó que este es un problema general para NODE, JAVA, C# y PYTHON , y desarrollaron un modulo que resuelve este problema de fondo y de una forma muy elegante, y el uso de agreggations ya no es un misterio.
Lo bueno de este enfoque es que el sistema que se describe a continuación (mongoCompass) permite usar comandos mongodb y pasarlos a instrucciones JAVA, C++ o Pyton, cosa que usualmente no es nada trivial si se desea algo realmente interesante.
Por ejemplo para hacer una búsqueda con Regex en una cadena uno encuentra mucha información en tutoriales mongo como hacerlo y comandos que si se usan en la consola mango funcionan sin ningún problema, pero cuando se desea implementar en instrucciones java, C++ o Pyton el cosa se pone complicada.
veamos un ejemplo : RegexMatch es la instrucciones para conseguir un Regex en mongo, el parámetro options :"i" hace que la búsqueda sea no case sentive.
El comando mongo es:
{ $regexMatch: { input: $citaHora , regex: "12:30 ", options: "i" } }
La instrucción equivalente JAVA es:
(new Document("$regexMatch", new Document("input", "$citaHora").append("regex", Pattern.compile("12:30")).append("optio\ns", "i"))
Como se ve transformar eel comando en instrucciones no es algo simple como dije anteriormente por eso esta herramienta (mongo Compass) considero es muy importante aprenderla a usar para facilitar esta labor.
Pues bien hay que instalar como es lógico desde el sitio de Mongo Compass que es un programa residente (no es en línea), hasta ahora me ha funcionado bien en Linux sin problemas.
Bueno una vez instalado y dando por supuesto que tiene mongo funcionado adecuadamente en consola, ( # mongo) el sistema abre una pantalla con todas las Colecciones con sus comandas de administración-
Desde esta pantalla selecciona una colección , es este caso seleccione gestion001 , dentro de ella elegí Correspondencias,
Observar que la segunda pestaña debajo de Correspondencias dice Aggregation, dar click sobre ella, para el caso que estoy presentando le dije que me hiciera una addFields ( es un comando muy útil porque puedo crear variables al vuelo que contengan diversos parámetros para comparar , mezclar, ordenar etc, por un campo que es virtual y se crea al momento de ejecución, observar a mitad de la pantalla como definí el campo que deseo que el Aggregation me calcule, este simple cálculo que con el modelo que expuse anteriormente es trivial, para determinar un fecha entre un intervalo de fechas como aquí,
myMatchAF.add(new Document("$gte", Arrays.asList("$visitanteFecha", fechaD_))) ;
myMatchAF.add(new Document("$lte", Arrays.asList("$visitanteFecha", fechaH_))) ;
Pues resulta que con agregation no lo es tanto por lo menos desde el punto de vista conceptual pero mas si espero que ese resultado que es la salida de una clausula AND deseo integrarla con otras pero de tipo OR. La cosa por lo menos para mi no fue de chiste.
Pero ahora con la ayuda de Compass y con addfields, la cosa fue a otro precio, primero creo el intervalo de interés en una addfields que me almacena una variable booleana, , y como es campo común y corriente actuó sobre ellas con cualquier otra comparación que quiera.
Bueno dejamos el tema y seguimos, ya me encontré en Internet las mil y una forma de hacer este aggregation con la consola mongo.
Que es la que dejo en la pantalla, para efectos de poder recuperar este contenido en caso de necesitarlo pues simplemente le digo SAVE, Observar que ha medida que el paso que estoy programando es exitoso (Compass permite auto completar tanto variables de la colección , como comando y clausulas validas) , el stage muestra a la derecha el resultado de la evaluación de la clausula, hay que tener cuidados con las llaves, paréntesis y comillas pues Compass es muy quisquilloso con eso , a la derecha de SAVE hay un icono que indica Export to Lenguge, dar click sobre él.
Se ve el comando tal cual fue programado y también la versión Java del mismo
Para tener una visión de las librerías utilizadas en el proceso , dar click en los botones, include en la parte inferior de la ventana derecha.
A mi ha servido mucho, hay que hacer varios ensayos hasta sentirse cómodo con el manejo, pero para mi, la principal virtud de este proceso es doble, lo primero de forma iterativa voy viendo el resultado de ir implementando los diferentes stage (etapas de consulta) y cuando tengo todo funcionado me proporciona el código correcto.
Una nota muy importante, observar que se genera en este caso particular de addFields, un :
new addFields(), en java versión 1.7 en adelantarte es necesario declarar el tipo de campo.
También observar que por lo general cuando clausula o comando que vamos a usar tiene mas de 2 variables el modelo en Java usa Arrays.asList (), para definir todos los parámetros necesarios.
Como en en este caso donde se vería algo algo como asi TerceroFecha >= FechaD_
tiene 3 parámetros por así decirlo
1. TerceroFecha
2. >= (“$gte”)
3. FechaD:
Algo similar a lo siguientes
new Document("$gte", Arrays.asList ("$terceroFecha", fechaD_))
Bson myMatchF ;
List<Bson> myMatchAF= new ArrayList<Bson>() ;
myMatchAF.add(new Document("$gte", Arrays.asList ("$terceroFecha", fechaD_))) ;
myMatchAF.add(new Document("$lte", Arrays.asList("$terceroFecha", fechaH_))) ;
myMatchF = and(myMatchAF) ;
myAddFieldsDate = addFields(new Field<Bson>("terceroDate",myMatchF)) ;
myList.add(myAddFieldsDate) ;
Un pequeño detalle en general Mongo Compass no deja copiar y pegar , todo se hace con los iconos para este propósito que la aplicacion tiene.
Comentarios
Publicar un comentario