JmoordbUnit con filtros entre fechas en List<entity> embebidos
Las bases de datos NoSQL, tales como MongoDB nos permiten gran flexibilidad comparados con bases de datos relacionales.
Por ejemplo en una base de datos de facturación de un sistema relacional, tendríamos una tabla de facturas y otra de Pagare, con cientos de registros asociados.
Mediante SQL podemos hacer consultas, en el ejemplo, buscamos en la tabla de pagare todas aquellas facturas con un estatus especifico y con la condición que estos pagares estén entre una fecha de inicio y de fin y que tengan el estatus de cancelado="no".
Usamos un select o un join, en el cual iteramos la consulta sobre dos tablas para obtener los resultados.
Ahora lo vemos desde una perspectiva NoQSL, en el cual podemos almacenar dentro de la colección Factura una lista embebida de Pagare. De manera que al consultar en la colección Factura, automáticamente tendremos acceso a los pagares que se almacenan en la misma colección.
Esquema del Json de Factura
- Utilizaremos ejbjmoord como APi para comunicarnos con MongoDB.
- jmoordbUnit para generar los test progresivos (Nos permiten generar ademas del test, una interfaz gráfica con las pruebas).
Pasos:
Creamos dos proyectos en NetBeans IDE
Un proyecto EJB Module llamado storejb
y otro proyecto de tipo Payara Micro Application llamado storetest
Clase Factura:
MOSTRAR TODAS LOS PAGARES
Usamos UnitTest para generar la salida del test.
unitTest.form();
unitTest.formTitle("Reporte de Todas las facturas con pagare");
unitTest.panel();
unitTest.panelAddTableHeader("Pagare", Arrays.asList(new RowView("idfactura"), new RowView("Pagare"), new RowView("Cancelado"),
new RowView("Fecha")));
flist.forEach((f) -> {
f.getPagare().forEach((p) -> {
unitTest.panelAddTableCol(Arrays.asList(new ColView(f.getIdfactura()), new ColView(p.getNumero()),
new ColView(p.getCancelado()),
new ColView(p.getFechavencimiento())
));
});
});
unitTest.panelAddTableClose();
unitTest.panelClose();
unitTest.formClose();
Podemos ver todos los pagares dentro de las facturas y las fechas de vencimiento y el valor de cancelado.
FILTRAR EL LIST<> EMBEBIDO.
Dibujamos las cajas de texto del filtro.
List<Factura> listFactura = facturaRepository.filters(filter, new Document("idfactura", 1));
unitTest.assertNotEquals(nameOfMethod(), 0, listFactura.size());
unitTest.form();
unitTest.formTitle("Filtro");
unitTest.panel();
unitTest.panelAddInputText(Arrays.asList(new InputText("desde", firstDate.toString()),
new InputText("hasta", lastDate.toString()), new InputText("cancelado", "no"))
);
unitTest.panelClose();
unitTest.buttonGreen("Filtrar");
unitTest.formClose();
Aplicamos el filtro generando un Filters para cada posición dentro del List<>
Filtramos cada elemento del List<> embebido indicando la posición dentro del List<>, por ejemplo pagare.0.cancelado, pagare.1.cancelado , y el filtro entre fechas. Utilizamos una función que denominamos functionFilter() que genera un solo Bson que contiene los filtros para cada posición.
Integer anio = 2019;
Integer mes = 4;
Date firstDate = DateUtil.primerDiaDelMesEnFecha(anio, mes);
Date lastDate = DateUtil.getDateLastOfMonth(anio, mes);
Bson filterfactura = Filters.and(Filters.eq("almacen.idalmacen", 6), Filters.or(Filters.eq("estatusfactura.idestatusfactura", 1), Filters.eq("estatusfactura.idestatusfactura", 2), Filters.eq("estatusfactura.idestatusfactura", 6), Filters.eq("estatusfactura.idestatusfactura", 7)));
Bson filterpagare = functionFilter(0, firstDate,lastDate);
for (int i = 1; i < 13; i++) {
Bson f = functionFilter(i, firstDate,lastDate);
filterpagare = Filters.or(filterpagare, f);
}
Bson filter = Filters.and(filterfactura, filterpagare);
Ejecutar el filtro
List<Factura> listFactura = facturaRepository.filters(filter, new Document("idfactura", 1));
Bson filter = Filters.and(filterfactura, filterpagare);
Ejecutar el filtro
List<Factura> listFactura = facturaRepository.filters(filter, new Document("idfactura", 1));
Función que genera el filtro para cada elemento
private Bson functionFilter(Integer i, Date startDate, Date lastDate) {
Bson filter = Filters.and(
Filters.gte("pagare." + i + ".fechavencimiento", startDate),
Filters.lte("pagare." + i + ".fechavencimiento", lastDate),
Filters.eq("pagare." + i + ".cancelado", "no")
);
return filter;
}
Se realiza el filtro correctamente, mostrando solo la factura 5.
Aplicar un filtro genérico sin indicar la posición dentro del List<>
Cuando usamos este filtro sin especificar la posición dentro del List<>. no funciona el and, se comporta como un or.
Bson filterfactura = Filters.and(Filters.eq("almacen.idalmacen", 6), Filters.or(Filters.eq("estatusfactura.idestatusfactura", 1), Filters.eq("estatusfactura.idestatusfactura", 2), Filters.eq("estatusfactura.idestatusfactura", 6), Filters.eq("estatusfactura.idestatusfactura", 7)));
Bson filterpagare = Filters.and(Filters.eq("pagare.cancelado", "no"),
Filters.gte("pagare.fechavencimiento", firstDate),
Filters.lte("pagare.fechavencimiento", lastDate)
);
Bson filter = Filters.and(filterfactura, filterpagare);
Observen que se genera un listado de todas las facturas que contengan un rango de fecha, pero ignora la condición cancelado = "no"
Aquí falla un filtro de ese tipo dentro de MongoDB, ya que el buscara en la lista cualquier pagare que tenga la condición entre fechas y cualquier pagare que tenga cancelado ="no", sin restringuir que sea el mismo pagare que se este buscando.
Recomendación:
- Cuando desee hacer filtros dentro de un List<> embebido genere todas las posiciones del list para hacer el filtro.
Comments