Últimamente me ha tocado trabajar con node.js consumiendo datos de la base de datos documental MongoDB y también desde SQL Server. Buscando información he podido probar varios conectores y paquetes que nos facilitan el trabajo a la hora de la conexión y de la creación de consultas.
Para conectarme con SQL Server he utilizado Tedious. Se trata de un paquete que puedes descargar vía npm
y que implementa el protocolo TDM. Tedious funciona tanto en servidores Linux como en Windows. El nombre de este paquete hace referencia a que la pronunciación en inglés de TDS es parecida a la de tedious (tedioso en inglés) 😁
Para la creación de consultas utilizo otro paquete llamado json-sql, que me permite crear consultas SQL a partir de objetos JSON (como por ejemplo en MongoDB). Ojo: este paquete se trata de un traductor, en ningún caso es un conector.
Su sintaxis es muy simple. Por ejemplo para realizar una consulta de selección hacemos lo siguiente:
1.- Importamos el paquete:
let jsonSql = require('json-sql');
Nos fijamos que ya estamos creando una instancia de json-sql
.
2.- Creamos una función para obtener el objeto que creará la consulta:
createSelectQuery(filter, sort) {
let sql = jsonSql.build({
dialect: 'mssql',
type: 'select',
table: 'Direcciones',
fields: ['Id', 'Cif', 'NombreRazonSocial',
'Direccion', 'CodigoPostal', 'Poblacion',
'Provincia', 'ComunidadAutonoma',
'Pais', 'FechaModificacion'],
condition: filter,
sort: sort
});
return sql;
}
Vamos a desglosar un poco esta función...
Primeramente destacamos el objeto jsonSql
, que es el principal de la biblioteca. Posee un método buid
al cual le podemos especificar, entre otros, los siguientes parámetros:
- El dialecto que vamos a utilizar (
'base'
, 'mssql'
, 'mysql'
, 'postgresql'
o 'sqlite'
).
- El tipo de consulta (en este caso
SELECT
)
- La tabla o tablas con las que vamos a trabajar (se pueden hacer joins, agrupaciones...)
- Los campos que queremos proyectar
- Los filtros (WHERE)
- La ordenación
- ...
En la función anterior, las variables filter
y sort
asignados a las propiedades condition
y sort
respectivamente, son documentos JSON. Por ejemplo:
let sql = jsonSql.build({
table: 'table',
condition: {Nombre: 'Miguel'}
sort: {a: 1, b: -1}
});
En este ejemplo el objeto sql
tiene una propiedad query
que contiene la consulta SQL resultante, así:
sql.query = 'select * from "table" WHERE Nombre = "Miguel" order by "a" asc, "b" desc';
3.- Una vez tenemos la consulta, vamos a atacar a la base de datos. Vamos a usar promesas para realizar llamadas asíncronas. Existe un paquete llamado bluebird que nos facilita mucho su creación. Veamos cómo usarlo:
3.1.- Importamos el paquete:
const promise = require('bluebird');
3.2.- He creado una función executeQuery
para gestionar la conexión con la base de datos y la ejecución de consultas en la que importo las clases SqlConnection
y Request
:
const SqlConnection = require("tedious").Connection;
const Request = require("tedious").Request;
executeQuery(query) {
let resultEntity = {
result: {},
error: null
};
return new promise((resolve, reject) => {
var connection = new SqlConnection(this.config);
connection.on('connect', function (err) {
let request = new Request(query, function (err, rowCount, rows) {
if (err) {
resultEntity.error = err;
reject(resultEntity);
} else {
resultEntity.result = rows;
resolve(resultEntity);
}
connection.close();
});
connection.execSql(request);
}
);
});
}
En esta función primero creo una entidad resultEntity
que será la que se devuelva con el resultado obtenido de la consulta e información en caso de que se produzca algún error. Después está la promise
, en la que se establece la conexión creando un objeto de tipo SqlConnection
al que se le pasa la configuración en el constructor. Esta configuración tiene el siguiente aspecto:
"config": {
"server": "servidor",
"userName": "Usuario",
"password": "clave",
"options": {
"instanceName": "Nombre de la instancia",
"database": "nombre base de datos",
"rowCollectionOnRequestCompletion": true,
"rowCollectionOnDone": true
}
}
Puedes encontrar más información al respecto de esta configuración en la documentación de Tedious.
A continuación nos subscribimos al evento connect
de la conexión y creamos un objeto de tipo request
, al cual le pasamos como primer parámetro la consulta a realizar. Este objeto request
va a ser el encargado de gestionar la consulta y devolver los resultados (rows
) o si se produce algún error (err
).
Se procede a cerrar la conexión:
connection.close();
Y después de la subscripción al evento connect
procedemos a ejecutar la consulta mediante el método execSql
de la conexión, el cual recibe como parámetro el objeto request
que acabamos de crear.
En definitiva lo que realiza esta función es:
- Crea el objeto a devolver por la función
- Crea el objeto de conexión
- Se subscribe al evento
connect
de la conexión
- Crea el objeto
request
para hacer la petición a la base de datos y recibir los resultados
- Ejecuta la consulta
El objeto recibido devuelve los valores de la consulta así como los metadatos de cada campo solicitado.
¡Espero que os sea de utilidad!