NocoBase 2.2.7 falla en actualizaciones condicionales atómicas por diseño
El filtrado se usa para la búsqueda pero se descarta en el UPDATE, lo que permite modificar filas que ya no cumplen la condición.

NocoBase 2.2.7 tiene un bug de concurrencia en su lógica de actualización masiva: el filtro que especificas en la petición no se aplica al comando SQL de UPDATE, solo al SELECT inicial. Esto significa que una fila que deja de cumplir la condición entre la búsqueda y la escritura sigue siendo modificada. El problema no es de rendimiento, es de integridad de datos.
El autor del análisis, tras un reporte en el foro oficial, revisó el código fuente de la última versión estable. En el paquete core/database, el método update de la clase repository utiliza un decorador @transaction() que agrupa la búsqueda y la actualización. Sin embargo, la implementación interna realiza un find con el filtro recibido, extrae las claves primarias de las filas resultantes y luego ejecuta una actualización por cada fila usando únicamente la clave primaria. La condición original desaparece del WHERE del UPDATE. El resultado es una actualización no atómica respecto a la condición: si el estado de la fila cambia en ese intervalo de tiempo (microsegundos o segundos, dependiendo del volumen), NocoBase la escribirá igualmente.
Para demostrarlo, el autor cargó más de 10.000 filas en PostgreSQL 16 y midió el comportamiento. En pruebas de 1,5 segundos con tablas pequeñas no se reproduce porque la operación termina antes de que pueda intervenir una concurrencia. Pero con tablas grandes, donde la actualización masiva tarda más de 6 segundos, la ventana de error es suficiente. En una prueba determinística usando bloqueos de base de datos (pg_sleep y BEGIN/COMMIT en otra sesión), se forzó la situación: se bloqueó la última fila por ID, se cambió su estado de pending a cancelled en otra transacción, y se dejó que NocoBase continuara. Cinco de cinco veces, NocoBase actualizó la fila aunque ya no coincidiera con el filtro status = 'pending'.
Si vienes de Django, este comportamiento es opuesto al de QuerySet.update(), que emite una sola sentencia SQL con la condición intacta. NocoBase opta por el bucle de Model.save() implícito, pero sin las señales ni la atomía de la condición. La única forma de evitar esto actualmente es reescribir la lógica para que la condición se incluya en el UPDATE, lo cual requiere modificar el código base o usar nodos SQL personalizados en los workflows, aunque la documentación de nodos SQL no cubre este caso específico de concurrencia.
El equipo de NocoBase respondió al reporte inicial en septiembre que estaban investigando, pero el problema persiste en la versión actual. Para equipos que dependen de actualizaciones condicionales atómicas en NocoBase, esta es una advertencia seria: no confíen en el filtro para garantizar que solo se modifiquen filas que cumplan la condición en el momento exacto de la escritura.


