JM

Prisma, ORMs y la paginación: Una reflexión sobre optimización y prioridades

Ju

Juan Daniel Martínez

Publicado en Junio 18, 2025

Imagen de portada del post

Estaba reflexionando bastante sobre las decisiones técnicas que tomamos, sobre todo cuando adoptamos herramientas porque son “modernas” o recomendadas por todos. A veces, cosas que damos por hecho pueden salirnos más caras de lo esperado.

Recientemente decidí retomar un poco mi rol como fullstack e ir construyendo proyectos poco a poco, aumentando la complejidad de mis implementaciones. Motivado por la comodidad y rapidez de desarrollo (además de que ya quería lanzar este blog lo más rápido posible), opté por pedir sugerencias a chatGPT y me fui directo a usar Prisma, un ORM muy popular para trabajar con bases de datos desde JavaScript.

Todo iba bastante bien hasta que llegó el momento de implementar una funcionalidad básica: la paginación de resultados. En ese momento tenía poco tiempo para dedicarle a la feature, así que entré en modo vibe coder y decidí pedirle a chatGPT una sugerencia. Me empezó a generar el código para la consulta en Prisma, que incluía propiedades que no había usado antes y que a simple vista se veían raras, así que opté por consultar la documentación oficial para verificar que el código fuera válido y ver cómo manejar eficientemente el conteo total de registros. Para mi sorpresa, encontré algo inesperado: ¡Prisma no tiene una función integrada para obtener los resultados y su conteo total en una sola consulta!

Sí, así como lo lees. Si quieres hacer algo tan sencillo como paginar resultados y mostrar cuántos registros hay en total, necesitas ejecutar dos consultas prácticamente idénticas: una para obtener los datos y otra para contar cuántos elementos hay. Esto implica ejecutar algo así:

const data = await prisma.model.findMany();
const count = await prisma.model.count();

Ahora imagínate el lío que sería si incrementas la complejidad de estas consultas, agregando filtros, condiciones, joins y demás... ¡un verdadero desastre!

Esto me hizo bastante ruido, especialmente viniendo del frontend, donde estamos muy acostumbrados a optimizar cada milisegundo para ofrecer una experiencia fluida al usuario. Investigué un poco más y encontré un issue donde precisamente se solicita esta funcionalidad (propuesta como una función llamada findManyAndCount). Tuve un pequeño momento de alegría que incluso me recordó a esos tiempos en que googleabas tus problemas y encontrabas un link de StackOverflow con exactamente el mismo problema que estabas enfrentando... desgraciadamente, la emoción me duró poco al notar que el issue seguía en estado Open 😣 y terminé de morir cuando vi que ha estado abierto desde el 2021 💀

Leyendo los comentarios, me di cuenta de que no soy el único sorprendido. Muchos usuarios con sistemas robustos y casos complejos de paginación expresan frustración ante la ausencia de esta simple funcionalidad. Las soluciones alternativas que mencionan incluyen usar prisma.$transaction, que aunque organiza mejor las consultas, las ejecuta de manera secuencial y por lo tanto, es más lenta (dependiendo del volumen de los datos):

const [data, count] = await prisma.$transaction([
  prisma.model.findMany(),
  prisma.model.count(),
]);

Otra alternativa más rápida sería utilizar Promise.all, ejecutando ambas consultas en paralelo:

const [data, count] = await Promise.all([
  prisma.model.findMany(),
  prisma.model.count(),
]);

Sin embargo, indagando más en los comentarios, alguien resaltó un caso interesante. Aunque estas soluciones parecen suficientes para implementaciones sencillas, traen consigo otro problema importante: ¿qué pasa si hay un INSERT o DELETE justo entre ambas consultas? Podríamos terminar con un resultado desalineado:

- Total count = 5
- Returned elements = 4

Esto refuerza algo que leí hace tiempo: un ORM nunca podrá reemplazar completamente las consultas SQL directas, especialmente cuando buscas optimizar al máximo tu aplicación. (Lo siento, esta vez no pude encontrar el tweet, pero se me quedó grabado en la mente).

Además, esta experiencia me llevó a preguntarme sobre la popularidad actual de herramientas como Prisma. ¿Realmente han ganado popularidad recientemente, o es solo mi percepción por haberlas empezado a usar ahora? Algo similar al fenómeno de que cuando compras cierto modelo de coche, de repente ves ese mismo coche en todos lados. Curioso cómo funciona eso.

En definitiva, esto no afecta demasiado mi caso de uso, donde la carga de datos es baja, pero sí me lleva a reflexionar sobre cómo elegimos nuestras herramientas y la importancia de revisar cuidadosamente sus limitaciones antes de adoptarlas completamente. Incluso con implementaciones que uno podría dar por hecho, siempre puedes llevarte sorpresas.

Me gustaría mucho conocer la experiencia de otros sobre este tema. ¿Han experimentado situaciones similares con Prisma u otros ORMs? ¿Consideran que la implementación directa de SQL sigue siendo necesaria para estos casos específicos? ¿Cómo evalúan ustedes estas prioridades dentro del desarrollo de herramientas como Prisma?

Déjenme sus comentarios y opiniones al respecto; creo que podemos aprender mucho discutiendo estas pequeñas (pero significativas) decisiones técnicas.