Imaginem que treballes en un sistema de gestió escolar. Tens un model de Resultats on, cada vegada que s'actualitza una nota, s'ha de recalcular automàticament la puntuació final i la qualificació. Implementes un hook pre('save') a Mongoose que fa aquest càlcul. Tot funciona perfectament quan crees i guardes un document directament. Però en utilitzar findByIdAndUpdate al teu endpoint d'actualització, et portes una sorpresa: els camps derivats no s'actualitzen. No hi ha errors, no hi ha logs, només dades obsoletes. Aquest escenari no és un bug de Mongoose; és un error conceptual que molts desenvolupadors cometen.
Aquest tipus de bug, que no llança excepcions ni crasheja, és el més perillós perquè produeix dades inconsistents de forma silenciosa. En el món del desenvolupament de programari empresarial, especialment quan es construeixen sistemes que integren intel·ligència artificial o agents IA, la consistència de les dades és fonamental. Un camp derivat desactualitzat pot alimentar un model de machine learning amb informació errònia, arruïnant prediccions i decisions automatitzades.
Per què passa? findByIdAndUpdate no carrega el document a memòria, no el muta ni crida a .save(). En lloc d'això, envia una operació d'actualització directament al driver de MongoDB. Això significa que els hooks pre('save') i post('save') — lligats al cicle de vida de save — simplement no s'executen. Existeix un hook pre('findOneAndUpdate'), però si només vas definir pre('save'), aquest camí se salta completament. La lliçó aquí és que hem de comprendre què ometen els mètodes abreujats, no només què fan.
La solució fiable és el patró fetch-mutate-save: cercar el document amb findById, modificar el camp i cridar a .save(). Això costa una volta extra a la base de dades, però garanteix que tota la lògica del hook s'executi. A Q2BSTUDIO apliquem aquest principi en tots els nostres projectes de desenvolupament d'aplicacions a mida, on la integritat de les dades és crítica. Sabem que un bug silenciós pot costar hores de depuració i, pitjor encara, generar dades incorrectes que passen desapercebudes fins que algú nota que les xifres no quadren.
Tot i que el patró fetch-mutate-save implica una consulta addicional, a la pràctica l'impacte en rendiment és mínim si la base de dades està optimitzada amb índexs adequats. A Q2BSTUDIO, en desenvolupar solucions de ciberseguretat, on cada transacció ha de quedar registrada sense inconsistències, preferim aquesta seguretat extra. De la mateixa manera, en projectes de Business Intelligence amb Power BI, la fiabilitat de les dades font és crítica perquè els dashboards reflecteixin la realitat.
Una altra alternativa és utilitzar el hook pre('findOneAndUpdate') i fer el càlcul manualment en aquesta funció, però això duplica la lògica de negoci i pot portar a divergències. Per això recomanem mantenir un únic punt de veritat: el hook pre('save'). Així, qualsevol actualització que passi per save — incloent les que vénen de fetch-mutate-save — executarà sempre la mateixa lògica. Aquest enfocament és especialment rellevant quan es treballa amb aplicacions a mida que evolucionen ràpidament i els requisits de càlcul canvien.
La temptació d'utilitzar dreceres com findByIdAndUpdate és gran perquè estalvien codi i semblen eficients. Però en models amb lògica de negoci en hooks pre('save'), és millor resistir-se. A Q2BSTUDIO hem vist com aquest tipus de decisions afecten sistemes complexos que integren núvol AWS/Azure, intel·ligència artificial, ciberseguretat i BI/Power BI. Per exemple, en un projecte d'agents IA que processen dades de clients en temps real, un error silenciós com aquest podria propagar resultats erronis a través de tot un pipeline analític.
La regla que adoptem és senzilla: si un esquema té hooks pre('save') significatius — camps derivats, validacions que depenen de múltiples camps, o qualsevol lògica més enllà de la validació bàsica — no utilitzis findByIdAndUpdate per defecte. Reserva aquestes dreceres per a actualitzacions simples de camps on cap efecte secundari del hook importi. Aquesta disciplina ha evitat innombrables maldecaps en projectes de programari a mida, especialment quan escalem cap a arquitectures al núvol o implementem solucions de ciberseguretat que requereixen traçabilitat absoluta.
Més enllà del codi, el veritable aprenentatge és preguntar-se sempre: què m'estic saltant en utilitzar aquest mètode abreujat? A Q2BSTUDIO, en desenvolupar aplicacions multiplataforma o sistemes de Business Intelligence amb Power BI, apliquem aquesta mentalitat en cada decisió tècnica. No es tracta de llegir millor la documentació (tot i que ajuda), sinó de comprendre el model mental subjacent. Mongoose documenta clarament que findByIdAndUpdate omet save hooks, però és fàcil assumir que 'actualitzar' sempre significa 'guardar'. Trencar aquesta associació és clau per escriure programari robust.
En resum, el bug de Mongoose que ens ensenya a evitar findByIdAndUpdate no és un error de la llibreria, sinó una invitació a reflexionar sobre les nostres suposicions. La propera vegada que utilitzis una drecera, pregunta't què estàs sacrificant. A Q2BSTUDIO ho tenim clar: la fiabilitat de les dades no és negociable, i de vegades la solució més directa (tres línies en lloc d'una) és la més segura.





