Otro post que escribo sobre GORM, un ORM de Go. En este caso vamos a ver cómo hacer una consulta manual y un escaneo manual, es decir, algo tipo raw. Algo así como una query personalizada.
Este tipo de consultas son poco comunes pero existen para cuando necesitamos hacer un reporte o traer ciertos datos que no corresponden a un único modelo.
En primer lugar comenzamos definiendo el modelo en donde vamos a escanear los valores. Yo voy a poner un ejemplo simple: un modelo que tiene una ganancia (es decir, un valor monetario) y un id del empleado que tiene esa ganancia.
type EmpleadoConGanancia struct {
IdEmpleado int64 `json:"idEmpleado" gorm:"column:id"`
Ganancia float64 `json:"ganancia"`
}
Fíjate en que aunque la columna en el struct se llama IdEmpleado
le estoy indicando a GORM que la columna que va a escanear sobre este valor será la que tenga el nombre de id
.
Por cierto, cada nombre de propiedad del struct debe coincidir con el nombre de columna de la tabla. Por ejemplo, si en la tabla existe una columna llamada id_usuario
la misma será tomada en cuenta si hay una propiedad llamada IdUsuario
.
Luego creamos el arreglo en donde vamos a colocar los valores:
var empleados []EmpleadoConGanancia
Ahora hago mi consulta y obtengo las filas. La sintaxis es:
filas, err := bd.Raw("consulta", posibles_parámetros...).Rows()
Es importante comprobar que el error es nil y cerrar las filas con filas.Close
(se puede usar defer). En mi caso:
rows, err := bd.Raw(`select sum(operaciones_de_cortes.precio * bultos_de_cortes.piezas) as ganancia,
empleados.id
from bihorarios
inner join bultos_de_empleados
on bihorarios.id_bulto_de_empleado = bultos_de_empleados.id
inner join operaciones_de_cortes
on operaciones_de_cortes.id = bultos_de_empleados.id_operacion_de_corte
inner join empleados
on bultos_de_empleados.id_empleado = empleados.id
inner join bultos_de_cortes
on bultos_de_cortes.id = bultos_de_empleados.id_bulto_de_corte
where bultos_de_empleados.fecha_terminacion != ''
and bultos_de_empleados.fecha_terminacion >= ?
and bultos_de_empleados.fecha_terminacion <= ?
group by empleados.id;`, fechaInicio, fechaFin).
Rows()
if err != nil {
return empleados, err
}
defer rows.Close()
Que no te confunda la consulta, solo te estoy colocando un ejemplo.
Finalmente, recorremos las filas, escaneamos y agregamos el valor al arreglo:
for rows.Next() {
var e EmpleadoConGanancia
bd.ScanRows(rows, &e)
empleados = append(empleados, e)
}
El código completo queda así; estoy omitiendo la parte en donde obtienes la conexión a la base de datos pues eso puede variar:
func consulta(fechaInicio, fechaFin string) ([]EmpleadoConGanancia, error) {
var empleados []EmpleadoConGanancia
bd, err := obtenerBd()
if err != nil {
return empleados, err
}
defer bd.Close()
rows, err := bd.Raw(`select sum(operaciones_de_cortes.precio * bultos_de_cortes.piezas) as ganancia,
empleados.id
from bihorarios
inner join bultos_de_empleados
on bihorarios.id_bulto_de_empleado = bultos_de_empleados.id
inner join operaciones_de_cortes
on operaciones_de_cortes.id = bultos_de_empleados.id_operacion_de_corte
inner join empleados
on bultos_de_empleados.id_empleado = empleados.id
inner join bultos_de_cortes
on bultos_de_cortes.id = bultos_de_empleados.id_bulto_de_corte
where bultos_de_empleados.fecha_terminacion != ''
and bultos_de_empleados.fecha_terminacion >= ?
and bultos_de_empleados.fecha_terminacion <= ?
group by empleados.id;`, fechaInicio, fechaFin).
Rows()
if err != nil {
return empleados, err
}
defer rows.Close()
for rows.Next() {
var e EmpleadoConGanancia
bd.ScanRows(rows, &e)
empleados = append(empleados, e)
}
return empleados, nil
}
Aquí tengo otro ejemplo más simple, en lenguaje Go usando Gorm:
type MateriaConConteoDeTarea struct {
Conteo int64 `json:"conteo"`
Materia string `json:"materia"`
IdMateria string `json:"idMateria"`
}
func obtenerMateriasConConteoDeTareas(idPeriodo int64) ([]MateriaConConteoDeTarea, error) {
materias := []MateriaConConteoDeTarea{}
bd, err := obtenerBd()
if err != nil {
return materias, err
}
defer bd.Close()
rows, err := bd.Raw(`select count(*) AS conteo,
materia.nombre AS materia, materia.id AS id_materia from tareas
inner join materia on materia.id = tareas.id_materia
where id_periodo = ? group by materia.id;`, idPeriodo).
Rows()
if err != nil {
return materias, err
}
defer rows.Close()
for rows.Next() {
var m MateriaConConteoDeTarea
bd.ScanRows(rows, &m)
if err != nil {
return materias, err
}
materias = append(materias, m)
}
return materias, bd.Error
}
Fíjate que en mi consulta SQL tengo las columnas llamadas conteo
, materia
e id_materia
. En mi struct corresponden, en el mismo orden, a Conteo
, Materia
e IdMateria
.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.