Instalación de SurrealDB: Base de Datos Multimodelo
SurrealDB es una base de datos innovadora que combina modelos de datos relacionales, de documentos y de grafos en un único sistema, eliminando la necesidad de múltiples bases de datos para diferentes casos de uso. Con SurrealQL (una extensión de SQL), soporte para suscripciones en tiempo real, autenticación integrada y una API HTTP nativa, SurrealDB simplifica enormemente el stack de datos de aplicaciones modernas en servidores Linux.
Requisitos Previos
- Ubuntu 20.04/22.04 o CentOS/Rocky Linux 8+
- Al menos 512 MB de RAM (2 GB recomendado para producción)
- Espacio en disco según el tamaño del dataset
- Acceso root o usuario con privilegios sudo
Instalación de SurrealDB
Instalación con el script oficial
# Instalar SurrealDB con el script de instalación oficial
curl -sSf https://install.surrealdb.com | sh
# El binario se instala en ~/.surrealdb/surreal
# Añadir al PATH
echo 'export PATH="$HOME/.surrealdb:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Verificar instalación
surreal version
Instalación manual del binario
# Detectar arquitectura
ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then ARCH="amd64"; fi
# Descargar binario para Linux
SURREAL_VERSION=$(curl -s https://api.github.com/repos/surrealdb/surrealdb/releases/latest \
| grep tag_name | cut -d '"' -f 4)
curl -L "https://github.com/surrealdb/surrealdb/releases/download/${SURREAL_VERSION}/surreal-${SURREAL_VERSION}.linux-${ARCH}.tgz" \
-o surreal.tgz
tar -xzf surreal.tgz
sudo mv surreal /usr/local/bin/
sudo chmod +x /usr/local/bin/surreal
surreal version
Crear servicio systemd
# Crear usuario del sistema
sudo useradd -r -s /bin/false surrealdb
sudo mkdir -p /var/lib/surrealdb
# Crear servicio systemd
sudo cat > /etc/systemd/system/surrealdb.service << 'EOF'
[Unit]
Description=SurrealDB Multi-Model Database
After=network.target
[Service]
Type=simple
User=surrealdb
Group=surrealdb
Environment=SURREAL_ROOT_USER=root
Environment=SURREAL_ROOT_PASS=contraseña_root_segura
ExecStart=/usr/local/bin/surreal start \
--bind 0.0.0.0:8000 \
--user root \
--pass contraseña_root_segura \
--log info \
file:/var/lib/surrealdb/data.db
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo chown surrealdb:surrealdb /var/lib/surrealdb
sudo systemctl daemon-reload
sudo systemctl enable surrealdb
sudo systemctl start surrealdb
Configuración y Arranque
# Iniciar SurrealDB en modo desarrollo (en memoria, sin persistencia)
surreal start --log debug memory &
# Iniciar con almacenamiento en archivo
surreal start \
--bind 0.0.0.0:8000 \
--user root \
--pass mi_contraseña \
--log info \
file:///var/lib/surrealdb/mydb.db
# Iniciar con RocksDB para producción (mejor rendimiento)
surreal start \
--bind 0.0.0.0:8000 \
--user root \
--pass mi_contraseña \
--log info \
rocksdb:///var/lib/surrealdb/rocksdb_data
# Conectar con la CLI de SurrealDB
surreal sql \
--conn http://localhost:8000 \
--user root \
--pass mi_contraseña \
--ns produccion \
--db mi_app
Namespaces y Bases de Datos
SurrealDB organiza los datos en namespaces y bases de datos:
-- Crear namespace y base de datos
DEFINE NAMESPACE produccion;
USE NS produccion;
DEFINE DATABASE mi_app;
USE NS produccion DB mi_app;
-- También se puede usar el formato corto en comandos:
-- surreal sql --ns produccion --db mi_app
-- Crear un usuario con acceso a la base de datos
DEFINE USER app_user ON DATABASE
PASSWORD 'app_contraseña'
ROLES EDITOR;
-- Revocar permisos
REMOVE USER app_user ON DATABASE;
-- Listar namespaces y bases de datos disponibles
INFO FOR ROOT;
INFO FOR NS;
INFO FOR DB;
SurrealQL: Consultas Avanzadas
SurrealQL extiende SQL con capacidades de documentos y grafos:
-- Crear tabla con schema
DEFINE TABLE producto SCHEMAFULL;
DEFINE FIELD nombre ON TABLE producto TYPE string;
DEFINE FIELD precio ON TABLE producto TYPE number ASSERT $value > 0;
DEFINE FIELD categoria ON TABLE producto TYPE string;
DEFINE FIELD activo ON TABLE producto TYPE bool DEFAULT true;
DEFINE FIELD creado_en ON TABLE producto TYPE datetime DEFAULT time::now();
-- Crear índice
DEFINE INDEX idx_categoria ON TABLE producto COLUMNS categoria;
-- Insertar documentos
INSERT INTO producto (nombre, precio, categoria) VALUES
('Servidor VPS Básico', 9.99, 'hosting'),
('Servidor Dedicado', 99.99, 'baremetal'),
('Almacenamiento NVMe', 19.99, 'storage');
-- CREATE con ID explícito
CREATE producto:vps_premium SET
nombre = 'VPS Premium',
precio = 29.99,
categoria = 'hosting',
activo = true;
-- Consultar datos
SELECT * FROM producto;
SELECT nombre, precio FROM producto WHERE categoria = 'hosting';
SELECT * FROM producto ORDER BY precio DESC LIMIT 5;
-- Actualizar documentos
UPDATE producto:vps_premium SET precio = 34.99;
UPDATE producto SET activo = false WHERE precio > 50;
-- Funciones de array y objetos
SELECT
nombre,
precio,
math::round(precio * 1.21, 2) AS precio_con_iva,
string::uppercase(categoria) AS categoria_mayus
FROM producto;
-- Subqueries
SELECT *,
(SELECT count() FROM pedido WHERE producto = $parent.id) AS total_pedidos
FROM producto;
Consultas de Grafo
Modelar y consultar relaciones con la sintaxis de grafo de SurrealQL:
-- Definir tablas para el grafo de relaciones
DEFINE TABLE usuario SCHEMAFULL;
DEFINE FIELD email ON TABLE usuario TYPE string;
DEFINE FIELD nombre ON TABLE usuario TYPE string;
DEFINE TABLE producto SCHEMAFULL;
DEFINE FIELD nombre ON TABLE producto TYPE string;
-- Definir la relación (arista del grafo)
DEFINE TABLE compra SCHEMALESS TYPE RELATION
FROM usuario TO producto
ENFORCED;
-- Crear registros
CREATE usuario:u1 SET email = '[email protected]', nombre = 'Juan';
CREATE usuario:u2 SET email = '[email protected]', nombre = 'María';
CREATE producto:p1 SET nombre = 'VPS Pro';
CREATE producto:p2 SET nombre = 'Servidor Dedicado';
-- Crear relaciones (aristas)
RELATE usuario:u1 -> compra -> producto:p1
SET fecha = time::now(), cantidad = 1, importe = 29.99;
RELATE usuario:u1 -> compra -> producto:p2
SET fecha = time::now(), cantidad = 1, importe = 99.99;
RELATE usuario:u2 -> compra -> producto:p1
SET fecha = time::now(), cantidad = 2, importe = 59.98;
-- Consultar con grafos: ¿Qué compró Juan?
SELECT ->compra->producto.nombre AS productos_comprados
FROM usuario:u1;
-- ¿Quién compró el VPS Pro?
SELECT <-compra<-usuario.nombre AS compradores
FROM producto:p1;
-- Travesía de grafos de varios niveles
-- ¿Qué otros productos compró gente que también compró VPS Pro?
SELECT ->compra->producto.nombre AS otros_productos
FROM usuario WHERE <-compra<-producto.nombre CONTAINS 'VPS Pro';
-- Grafo de recomendaciones (colaborativo)
SELECT ->compra->producto<-compra<-usuario->compra->producto.nombre AS recomendados
FROM usuario:u1;
Suscripciones en Tiempo Real
Recibir cambios en tiempo real via WebSocket:
# Las suscripciones en tiempo real se usan desde el cliente SDK
# Ejemplo con el SDK de JavaScript/TypeScript:
cat > /tmp/surrealdb-realtime.js << 'EOF'
import Surreal from 'surrealdb.js';
const db = new Surreal();
async function main() {
// Conectar a SurrealDB
await db.connect('ws://localhost:8000/rpc', {
namespace: 'produccion',
database: 'mi_app',
auth: {
username: 'root',
password: 'mi_contraseña'
}
});
// Suscribirse a cambios en la tabla producto
const queryId = await db.live('producto', (action, result) => {
console.log(`Evento: ${action}`);
console.log('Datos:', result);
});
console.log(`Suscripción activa: ${queryId}`);
// Insertar un registro para probar
await db.create('producto', {
nombre: 'VPS Nuevo',
precio: 15.99,
categoria: 'hosting'
});
// Mantener la conexión activa
// Para cancelar la suscripción: await db.kill(queryId);
}
main();
EOF
# Instalar el SDK y ejecutar
npm install surrealdb.js
node /tmp/surrealdb-realtime.js
También via la API HTTP con Server-Sent Events:
# Suscribirse a cambios via HTTP
curl -N http://localhost:8000/key/producto \
-H "NS: produccion" \
-H "DB: mi_app" \
-u "root:mi_contraseña" \
-H "Accept: text/event-stream"
Autenticación y Permisos
Sistema de autenticación y autorización integrado:
-- Definir un scope de usuario (para aplicaciones con usuarios propios)
DEFINE SCOPE usuarios_app
SESSION 14d
SIGNUP (CREATE usuario SET
email = $email,
password = crypto::argon2::generate($password),
nombre = $nombre
)
SIGNIN (SELECT * FROM usuario
WHERE email = $email
AND crypto::argon2::compare(password, $password)
);
-- Definir permisos a nivel de tabla
DEFINE TABLE pedido SCHEMAFULL
PERMISSIONS
FOR select WHERE creado_por = $auth.id
FOR create WHERE $auth.id IS NOT NULL
FOR update, delete WHERE creado_por = $auth.id;
DEFINE FIELD creado_por ON TABLE pedido TYPE record(usuario);
# Registrar un nuevo usuario en el scope
curl -X POST http://localhost:8000/signup \
-H "NS: produccion" \
-H "DB: mi_app" \
-H "Content-Type: application/json" \
-d '{
"ns": "produccion",
"db": "mi_app",
"sc": "usuarios_app",
"email": "[email protected]",
"password": "contraseña_usuario",
"nombre": "Nuevo Usuario"
}'
# Autenticar un usuario existente
curl -X POST http://localhost:8000/signin \
-H "NS: produccion" \
-H "DB: mi_app" \
-H "Content-Type: application/json" \
-d '{
"ns": "produccion",
"db": "mi_app",
"sc": "usuarios_app",
"email": "[email protected]",
"password": "contraseña_usuario"
}'
# Devuelve: {"code": 200, "token": "JWT_TOKEN"}
Despliegue con Docker
# Docker Compose para producción
mkdir -p /opt/surrealdb && cd /opt/surrealdb
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
surrealdb:
image: surrealdb/surrealdb:latest
restart: unless-stopped
command: >
start
--bind 0.0.0.0:8000
--user root
--pass ${SURREAL_ROOT_PASS}
--log info
rocksdb:/data/rocksdb
ports:
- "8000:8000"
volumes:
- surrealdb_data:/data
environment:
SURREAL_LOG: info
volumes:
surrealdb_data:
EOF
# Crear archivo .env con contraseñas
cat > .env << 'EOF'
SURREAL_ROOT_PASS=contraseña_root_muy_segura
EOF
docker-compose up -d
docker-compose logs -f surrealdb
Configurar Nginx como proxy inverso:
sudo cat > /etc/nginx/sites-available/surrealdb << 'EOF'
# Proxy para SurrealDB con soporte WebSocket
server {
listen 443 ssl http2;
server_name db.mi-dominio.com;
ssl_certificate /etc/letsencrypt/live/db.mi-dominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/db.mi-dominio.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Soporte WebSocket para suscripciones en tiempo real
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/surrealdb /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Solución de Problemas
SurrealDB no arranca (error de puerto en uso):
# Verificar qué proceso usa el puerto 8000
ss -tlnp | grep 8000
# Cambiar el puerto de SurrealDB
# En el comando de arranque: --bind 0.0.0.0:8001
Error de autenticación en consultas:
# Verificar que el namespace y la base de datos existen
surreal sql --conn http://localhost:8000 -u root -p contraseña \
--query "INFO FOR ROOT;"
# Verificar credenciales
surreal sql --conn http://localhost:8000 \
--user root --pass contraseña \
--ns produccion --db mi_app \
--query "INFO FOR DB;"
Las consultas de grafo devuelven resultados vacíos:
# Verificar que las relaciones existen
surreal sql ... --query "SELECT * FROM compra;"
# Verificar la sintaxis de la travesía de grafo
# ->relacion->destino para relaciones de salida
# <-relacion<-origen para relaciones de entrada
Conclusión
SurrealDB representa una nueva generación de bases de datos que elimina la necesidad de múltiples sistemas especializados al combinar el modelo relacional, documentos y grafo en una única plataforma. Su autenticación y autorización integradas a nivel de base de datos simplifican la arquitectura de las aplicaciones, mientras que las suscripciones en tiempo real via WebSocket facilitan el desarrollo de aplicaciones reactivas. Para proyectos que requieren flexibilidad en el modelo de datos y no quieren gestionar múltiples sistemas de bases de datos, SurrealDB es una propuesta técnica sólida con un ecosistema de SDKs en rápido crecimiento.


