El objetivo no es simplemente trasladar tablas de un motor a otro. Es conservar el significado de las relaciones cuando en el modelo de destino se organiza la información de una manera diferente.
1. El problema, antes de hablar de herramientas
Este laboratorio utiliza cuatro tablas ficticias: clientes, pedidos, líneas de pedido y pagos. En el origen, cada relación se representa mediante una clave. En el destino, queremos que un pedido pueda leerse como una unidad: sus líneas y pagos estarán incluidos en el mismo documento.
ordersorder_lines → order_idpayments → order_idorder├─ lines[]└─ payments[]El cambio parece mecánico, pero introduce decisiones: qué entidad define el límite del documento, qué relaciones se anidan, cuáles se referencian, cómo se actualizan y qué hacemos si el origen contiene una relación inválida.
2. El contrato de corrección
Antes de implementar, el proyecto define qué significa que una migración sea correcta. Estos invariantes son comprobables y no dependen de revisar manualmente unas cuantas filas.
3. Recorrido de un lote
- Fijar el alcance. Se obtiene una página estable de pedidos, ordenada por una clave que no cambia durante la ejecución.
- Extraer relaciones. Las líneas y los pagos se consultan únicamente para los identificadores del lote, evitando cargar tablas completas.
- Indexar en memoria. Las relaciones se agrupan por
order_idpara evitar búsquedas repetidas de coste cuadrático. - Construir documentos. La transformación es una función pura: recibe filas y devuelve documentos sin escribir todavía en el destino.
- Validar. Esquema, invariantes y tamaño se comprueban antes de decidir cuáles documentos se cargan y cuáles se aíslan.
- Cargar y reconciliar. Se realiza un upsert por clave natural y se comparan contadores y totales con el origen.
4. Decisiones y compromisos
Anidar o referenciar
Las líneas se consultan casi siempre con el pedido y tienen un ciclo de vida dependiente, por eso se anidan. El cliente se mantiene como referencia: puede cambiar de forma independiente y copiarlo completo en cada pedido multiplicaría actualizaciones. No es una regla universal; deriva del patrón de acceso supuesto.
Idempotencia
Un reintento no debe crear una segunda versión del mismo pedido. La clave del origen se conserva como identificador estable y la carga usa upsert. Esto resuelve duplicados, pero ojo, no garantiza por sí solo consistencia si un lote queda a medias: el informe debe registrar el punto de control y permitir repetirlo.
Tamaño del lote
Un lote grande reduce viajes a la base de datos, pero aumenta memoria, tiempo de recuperación y tamaño de la transacción. El tamaño será configurable y se medirá con tres señales: duración, memoria máxima y documentos procesados por segundo.
Documentos demasiado grandes
Aislarlos evita bloquear toda la ejecución, pero también puede esconder un error de modelado. La cuarentena no será el estado final: se registrará identificador, tamaño, regla infringida y acción necesaria para decidir si dividir el documento o revisar la frontera de agregación.
5. Fallos que el conjunto sintético debe provocar
El camino correcto solo demuestra una parte del sistema. El generador asignará un código estable para cada anomalía para que el fallo pueda repetirse y verificarse.
- F01: línea sin pedido; debe quedar en cuarentena.
- F02: pedido duplicado; el lote debe rechazarse antes de cargar.
- F03: importe con tipo incompatible; debe informar campo y valor.
- F04: pago llegado después del corte; debe entrar en la siguiente ejecución.
- F05: total incoherente; debe impedir la reconciliación del lote.
- F06: documento sobre el umbral; debe aislarse sin perder trazabilidad.
6. Qué observaremos
Un mensaje de «proceso terminado» no permite operar el sistema. Cada ejecución generará un resumen estructurado con identificador, ventana procesada, registros leídos, documentos escritos, actualizados y rechazados, duración por etapa y último punto de control confirmado.
{
"run_id": "run-0042",
"source_orders": 1000,
"inserted": 972,
"updated": 24,
"quarantined": 4,
"reconciled": true,
"checkpoint": 18420
}Estas cifras serán generadas por las pruebas, no escritas a mano en la página. La condición de éxito combinará ejecución técnica, reconciliación y ausencia de errores no clasificados.
7. Qué puede aprender cada lector
Verás cómo pasar de tablas relacionadas a documentos, separar extracción, transformación y carga, convertir reglas en validaciones y escribir pruebas que no dependen de datos reales.
Podrás discutir la frontera del agregado, consistencia de la lectura, idempotencia, recuperación parcial, estrategia de paginación, reconciliación, observabilidad y cuándo el modelo documental deja de ser apropiado.
8. Límites del caso
Este proyecto no pretende simular una migración empresarial completa. No cubre replicación continua, coexistencia prolongada de ambos sistemas, autorización, cifrado, despliegue multi-región ni acuerdos de nivel de servicio. Esos temas se enumeran como extensiones, ya que incluirlos impediría explicar y probar con claridad el núcleo del problema.
9. Resultado reproducido
La implementación se ejecutó de extremo a extremo con Oracle Free y MongoDB 7. Se generaron 250 pedidos sintéticos y se procesaron en tres lotes. La suma de origen y destino coincidió exactamente: 28.141,44.
El análisis estático y ocho pruebas automáticas pasan bien. Durante la prueba integral se detectó y corrigió una diferencia real de tipos: Oracle devolvía un campo numérico como float y el transformador exigía Decimal. La conversión se fijó en el adaptador de entrada y fue protegida también en la transformación.
10. Estado de publicación
El generador, el pipeline, las pruebas, la arquitectura y los comandos de ejecución están publicados en un repositorio independiente. GitHub Actions ejecuta el análisis estático y las ocho pruebas en cada cambio; la primera validación terminó correctamente.
Ver código y documentación en GitHub