Importacion y Exportacion de JSONL en Bases de Datos: PostgreSQL, MongoDB y Mas
Una guia completa para importar archivos JSONL a bases de datos y exportar registros de bases de datos como JSONL. Cubre comandos COPY de PostgreSQL, herramientas CLI de MongoDB, JSON_TABLE de MySQL, scripts de SQLite y patrones de importacion masiva listos para produccion.
Ultima actualizacion: febrero 2026
Por que Usar JSONL para Importacion y Exportacion de Bases de Datos?
JSONL (JSON Lines) se ha convertido en un formato preferido para mover datos entre bases de datos y sistemas externos. Cada linea es un objeto JSON independiente y autocontenido, lo que significa que puedes transmitir registros uno a la vez sin cargar todo el dataset en memoria. Esto es critico cuando estas migrando millones de filas entre instancias de PostgreSQL, sincronizando colecciones de MongoDB con un data warehouse o alimentando exportaciones de bases de datos a pipelines de aprendizaje automatico.
Comparado con CSV, JSONL preserva los tipos de datos, soporta objetos y arrays anidados y elimina la ambiguedad del escape de delimitadores. Un archivo JSONL puede transportar una columna jsonb de PostgreSQL exactamente tal cual, mientras que CSV requeriria que aplanes o escapes la estructura anidada. Comparado con un array JSON completo, JSONL es transmisible: puedes procesar, validar o transformar cada registro en el momento en que se lee, en lugar de esperar a que se parsee el archivo completo.
Todos los principales sistemas de bases de datos ahora tienen herramientas para JSONL. PostgreSQL puede hacer COPY de filas mediante conversion a jsonb, MongoDB viene con mongoimport y mongoexport que usan JSONL por defecto, MySQL 8.0 agrego JSON_TABLE para extraccion estructurada y SQLite tiene una extension JSON1. En las siguientes secciones, aprenderas los comandos exactos, scripts y mejores practicas para cada base de datos.
PostgreSQL: Importar y Exportar JSONL
PostgreSQL ofrece varios enfoques para trabajar con JSONL. El comando COPY proporciona la ruta de importacion masiva mas rapida, mientras que el tipo de datos jsonb te permite almacenar y consultar datos semi-estructurados de forma nativa. Para tablas estructuradas, puedes parsear campos JSONL en columnas tipadas durante la importacion.
La forma mas rapida de importar JSONL a PostgreSQL es cargar cada linea como un valor jsonb usando el comando COPY. Crea una tabla con una unica columna jsonb, luego usa COPY FROM para transmitir el archivo directamente a la base de datos.
-- Create a staging table with a single jsonb columnCREATE TABLE staging_import (data jsonb);-- Import the JSONL file (each line becomes one row)\COPY staging_import (data) FROM 'users.jsonl';-- Verify the importSELECT count(*) FROM staging_import;SELECT data->>'name' AS name, data->>'email' AS emailFROM staging_importLIMIT 5;-- Move data into a structured tableINSERT INTO users (name, email, age)SELECTdata->>'name',data->>'email',(data->>'age')::intFROM staging_import;
Para exportar datos como JSONL, usa row_to_json() o to_jsonb() para convertir cada fila en un objeto JSON, luego haz COPY del resultado a un archivo. Cada fila se convierte en una linea en el archivo de salida.
-- Export entire table as JSONL\COPY (SELECT row_to_json(t)FROM (SELECT id, name, email, created_at FROM users) t) TO 'users_export.jsonl';-- Export with filtering and transformation\COPY (SELECT row_to_json(t)FROM (SELECT id, name, email,created_at::text AS created_atFROM usersWHERE active = trueORDER BY id) t) TO 'active_users.jsonl';-- Verify: each line is valid JSON-- {"id":1,"name":"Alice","email":"alice@example.com",...}
Para cargas de trabajo de produccion, usa un script Python con psycopg2 para leer un archivo JSONL e insertar registros en columnas tipadas. Esto te da control total sobre la validacion, manejo de errores y tamano de lotes.
import jsonimport psycopg2from psycopg2.extras import execute_valuesdef import_jsonl_to_postgres(file_path, conn_string):conn = psycopg2.connect(conn_string)cur = conn.cursor()batch = []batch_size = 1000total = 0with open(file_path, 'r') as f:for line_num, line in enumerate(f, 1):line = line.strip()if not line:continuetry:record = json.loads(line)batch.append((record['name'],record['email'],record.get('age'),))except (json.JSONDecodeError, KeyError) as e:print(f"Skipping line {line_num}: {e}")continueif len(batch) >= batch_size:execute_values(cur,"INSERT INTO users (name, email, age) ""VALUES %s ON CONFLICT (email) DO NOTHING",batch)total += len(batch)batch = []print(f"Imported {total} records...")if batch:execute_values(cur,"INSERT INTO users (name, email, age) ""VALUES %s ON CONFLICT (email) DO NOTHING",batch)total += len(batch)conn.commit()cur.close()conn.close()print(f"Done. Imported {total} records.")# Usageimport_jsonl_to_postgres('users.jsonl', 'postgresql://localhost/mydb')
MongoDB: Soporte Nativo para JSONL
MongoDB tiene soporte de primera clase para JSONL a traves de sus herramientas de linea de comandos Database Tools. Las utilidades mongoimport y mongoexport usan el formato JSONL por defecto, lo que hace de MongoDB una de las bases de datos mas faciles para trabajar con intercambio de datos JSONL. Cada linea en un archivo JSONL se mapea directamente a un documento MongoDB.
mongoimport lee un archivo JSONL e inserta cada linea como un documento en la coleccion especificada. Soporta modo upsert, coercion de tipos de campos e insercion paralela para alto rendimiento.
# Basic import: each line becomes a documentmongoimport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--file=users.jsonl# Upsert mode: update existing documents by _idmongoimport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--file=users.jsonl \--mode=upsert \--upsertFields=email# Drop collection before import (clean slate)mongoimport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--file=users.jsonl \--drop# Import with parallel workers for large filesmongoimport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--file=large_users.jsonl \--numInsertionWorkers=4
mongoexport escribe cada documento de una coleccion como una unica linea JSON. Puedes filtrar, proyectar y ordenar la salida. El resultado es un archivo JSONL valido listo para ser procesado por cualquier sistema posterior.
# Export entire collection as JSONL (default format)mongoexport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--out=users_export.jsonl# Export with query filtermongoexport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--query={"active": true} \--out=active_users.jsonl# Export specific fields onlymongoexport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--fields=name,email,created_at \--out=users_partial.jsonl# Export with sortingmongoexport \--uri="mongodb://localhost:27017/mydb" \--collection=users \--sort={"created_at": -1} \--out=users_sorted.jsonl
MySQL: JSONL con JSON_TABLE y Scripts
MySQL no tiene un comando de importacion JSONL integrado como MongoDB, pero MySQL 8.0 introdujo JSON_TABLE que te permite extraer datos estructurados de cadenas JSON. Para importacion masiva de JSONL, el enfoque mas confiable combina LOAD DATA INFILE para carga bruta con JSON_TABLE para extraccion, o usa un lenguaje de scripting como Python.
Carga el archivo JSONL como texto crudo en una tabla de staging, luego usa JSON_TABLE para extraer campos en una tabla estructurada. Este enfoque de dos pasos funciona completamente dentro de MySQL.
-- Step 1: Create a staging table for raw linesCREATE TABLE jsonl_staging (id INT AUTO_INCREMENT PRIMARY KEY,raw_line TEXT NOT NULL);-- Step 2: Load the JSONL file as raw textLOAD DATA INFILE '/var/lib/mysql-files/users.jsonl'INTO TABLE jsonl_stagingLINES TERMINATED BY '\n'(raw_line);-- Step 3: Extract structured data with JSON_TABLEINSERT INTO users (name, email, age)SELECT jt.name, jt.email, jt.ageFROM jsonl_staging,JSON_TABLE(raw_line, '$'COLUMNS (name VARCHAR(255) PATH '$.name',email VARCHAR(255) PATH '$.email',age INT PATH '$.age')) AS jt;-- Step 4: Clean up staging tableDROP TABLE jsonl_staging;-- Verify the importSELECT * FROM users LIMIT 5;
Para mas flexibilidad, usa un script Python con mysql-connector-python para leer un archivo JSONL e insertar registros por lotes. Este enfoque maneja archivos grandes de forma eficiente y proporciona informes de errores detallados.
import jsonimport mysql.connectordef import_jsonl_to_mysql(file_path, config):conn = mysql.connector.connect(**config)cursor = conn.cursor()batch = []batch_size = 1000total = 0insert_sql = ("INSERT INTO users (name, email, age) ""VALUES (%s, %s, %s) ""ON DUPLICATE KEY UPDATE name=VALUES(name)")with open(file_path, 'r') as f:for line_num, line in enumerate(f, 1):line = line.strip()if not line:continuetry:record = json.loads(line)batch.append((record['name'],record['email'],record.get('age'),))except (json.JSONDecodeError, KeyError) as e:print(f"Skipping line {line_num}: {e}")continueif len(batch) >= batch_size:cursor.executemany(insert_sql, batch)conn.commit()total += len(batch)batch = []print(f"Imported {total} records...")if batch:cursor.executemany(insert_sql, batch)conn.commit()total += len(batch)cursor.close()conn.close()print(f"Done. Imported {total} records.")# Usageimport_jsonl_to_mysql('users.jsonl', {'host': 'localhost','user': 'root','password': 'secret','database': 'mydb'})
SQLite: Importacion Ligera de JSONL
SQLite es una excelente opcion para desarrollo local y datasets mas pequenos. Aunque SQLite no tiene un comando de importacion JSONL nativo, su extension JSON1 proporciona json_extract() para trabajar con datos JSON, y un simple script Python puede importar archivos JSONL de manera eficiente usando el soporte integrado de transacciones de SQLite.
Usa el modulo sqlite3 integrado de Python para leer un archivo JSONL e insertar registros en una base de datos SQLite. Envolver todas las inserciones en una unica transaccion mejora dramaticamente el rendimiento para archivos grandes.
import jsonimport sqlite3def import_jsonl_to_sqlite(jsonl_path, db_path):conn = sqlite3.connect(db_path)cursor = conn.cursor()# Create table if it doesn't existcursor.execute("""CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,email TEXT UNIQUE,age INTEGER,raw_json TEXT)""")total = 0errors = 0with open(jsonl_path, 'r') as f:# Use a transaction for bulk insert performanceconn.execute('BEGIN TRANSACTION')for line_num, line in enumerate(f, 1):line = line.strip()if not line:continuetry:record = json.loads(line)cursor.execute("INSERT OR IGNORE INTO users ""(name, email, age, raw_json) ""VALUES (?, ?, ?, ?)",(record['name'],record.get('email'),record.get('age'),line, # Store original JSON))total += 1except (json.JSONDecodeError, KeyError) as e:errors += 1print(f"Line {line_num}: {e}")conn.commit()conn.close()print(f"Imported {total} records, {errors} errors")# Usageimport_jsonl_to_sqlite('users.jsonl', 'app.db')# Query with json_extract (SQLite JSON1 extension)# SELECT json_extract(raw_json, '$.name') FROM users;
Mejores Practicas de Importacion Masiva
Importar archivos JSONL grandes a una base de datos requiere atencion cuidadosa a las transacciones, manejo de errores y gestion de recursos. Estas mejores practicas se aplican a todos los sistemas de bases de datos y te ayudaran a construir pipelines de importacion confiables y listos para produccion.
Transacciones por Lotes
RendimientoNunca insertes una fila por transaccion. Agrupa las inserciones en lotes de 500-5000 filas por transaccion. Esto reduce el I/O de disco y la sobrecarga de bloqueos entre 10 y 100 veces. La mayoria de las bases de datos ven las mayores ganancias con tamanos de lote de 1000. Ir mas grande ofrece retornos decrecientes y aumenta el costo de un rollback si algo falla.
Manejo de Errores por Linea
ConfiabilidadParsea y valida cada linea JSONL individualmente. Registra el numero de linea y el mensaje de error para cualquier linea que falle la validacion o insercion. Usa ON CONFLICT / ON DUPLICATE KEY para manejar violaciones de restricciones unicas de forma elegante en lugar de abortar toda la importacion. Guarda las lineas fallidas en un archivo de errores separado para revision posterior.
Seguimiento de Progreso
ObservabilidadPara archivos con millones de lineas, registra el progreso cada N registros (por ejemplo, cada 10,000). Rastrea el total de lineas leidas, inserciones exitosas, duplicados omitidos y errores. Calcula y muestra la tasa de importacion (registros/segundo) para identificar cuellos de botella de rendimiento. Esta retroalimentacion es esencial para monitorear importaciones de larga duracion.
Este patron generico combina agrupacion por lotes, manejo de errores y seguimiento de progreso. Adaptalo a cualquier base de datos intercambiando la funcion de insercion.
import jsonimport timedef batch_import_jsonl(file_path, insert_fn, batch_size=1000):"""Generic JSONL batch importer with error handling."""batch = []stats = {'total_lines': 0,'imported': 0,'skipped': 0,'errors': 0}start_time = time.time()error_file = open(file_path + '.errors', 'w')with open(file_path, 'r') as f:for line_num, line in enumerate(f, 1):stats['total_lines'] = line_numline = line.strip()if not line:stats['skipped'] += 1continuetry:record = json.loads(line)batch.append(record)except json.JSONDecodeError as e:stats['errors'] += 1error_file.write(f"{line_num}\t{e}\t{line}\n")continueif len(batch) >= batch_size:inserted = insert_fn(batch)stats['imported'] += insertedbatch = []if line_num % 10000 == 0:elapsed = time.time() - start_timerate = stats['imported'] / elapsedprint(f"Progress: {line_num:,} lines | "f"{stats['imported']:,} imported | "f"{rate:,.0f} records/sec")# Flush remaining batchif batch:inserted = insert_fn(batch)stats['imported'] += insertederror_file.close()elapsed = time.time() - start_timeprint(f"\nComplete in {elapsed:.1f}s")print(f" Lines: {stats['total_lines']:,}")print(f" Imported: {stats['imported']:,}")print(f" Errors: {stats['errors']:,}")return stats
Prepara tus Datos con Herramientas JSONL Gratuitas
Antes de importar JSONL a tu base de datos, valida el formato del archivo y convierte entre formatos. Nuestras herramientas online gratuitas procesan todo localmente en tu navegador, asi que tus datos nunca salen de tu maquina.