4 votes

Mongoose n'est-il pas extensible avec l'édition de tableaux de documents et le contrôle des versions ?

Je développe une application web avec Node.js et MongoDB/Mongoose. Notre modèle le plus utilisé, Record, possède de nombreux tableaux de sous-documents. Certains d'entre eux, par exemple, incluent "Comment", "Bookings", et "Subscribers".

Dans l'application côté client, chaque fois que l'utilisateur appuie sur le bouton "supprimer", il lance une requête AJAX vers la route de suppression pour ce commentaire spécifique. Le problème que je rencontre est que, lorsque plusieurs de ces appels AJAX arrivent en même temps, Mongoose échoue avec une erreur "Document non trouvé" sur certains (mais pas tous) des appels.

Le présent seulement se produit lorsque les appels sont effectués rapidement et en grand nombre. Je pense que cela est dû au fait que la version dans Mongoose provoque des conflits de documents. Notre processus actuel de suppression est le suivant :

  1. Récupérer le document à l'aide de Record.findById()
  2. Retirer le sous-document du tableau approprié (en utilisant, par exemple, comment.remove() )
  3. Appeler record.save()

J'ai trouvé une solution qui me permet de mettre à jour manuellement la collection à l'aide de Record.findByIdAndUpdate et en utilisant ensuite le $pull opérateur. Cependant, cela signifie que nous ne pouvons utiliser aucun des intergiciels de Mongoose et que nous perdons entièrement le contrôle de la version. Et plus j'y pense, plus je me rends compte des situations où cela se produirait et où je devrais utiliser les fonctions enveloppantes de Mongoose comme findByIdAndUpdate o findAndRemove . La seule autre solution à laquelle je peux penser serait de placer la tentative d'enlèvement dans une while en espérant que cela fonctionne, ce qui semble être une très mauvaise solution.

L'utilisation des wrappers Mongoose ne résout pas vraiment mon problème puisqu'elle ne me permet pas d'utiliser une quelconque sorte de Middleware ou de hooks, ce qui est pourtant l'un des grands avantages de l'utilisation de Mongoose.

Cela signifie-t-il que Mongoose est essentiellement inutile pour tout ce qui concerne l'édition rapide et que je ferais mieux d'utiliser les pilotes MongoDB natifs ? Ai-je mal compris les limites de Mongoose ? Comment puis-je résoudre ce problème ?

7voto

JohnnyHK Points 61191

L'édition de tableaux de documents versionnés de Mongoose n'est pas extensible pour la simple raison qu'il ne s'agit pas d'une opération atomique. Par conséquent, plus vous avez d'activités d'édition de tableaux, plus il est probable que deux éditions entrent en collision et que vous subissiez les frais généraux de réessai/récupération de cette situation dans votre code.

Pour une manipulation évolutive des tableaux de documents, vous devez utiliser update avec la mise à jour du tableau atomique opérateurs : $pull[All] , $push[All] , $pop , $addToSet y $ . Bien entendu, vous pouvez également utiliser ces opérateurs avec l'opérateur atomique findAndModify -Les méthodes d'évaluation de l'efficacité des findByIdAndUpdate y findOneAndUpdate si vous avez également besoin de l'original ou du document résultant.

Comme vous l'avez mentionné, le principal inconvénient de l'utilisation des update au lieu de findOne + save est qu'aucun de vos logiciels intermédiaires et de validation Mongoose n'est exécuté lors d'une session de update . Mais je ne pense pas que vous ayez le choix si vous voulez un système évolutif. Je préfère de loin dupliquer manuellement un intergiciel et une logique de validation pour le cas de la mise à jour plutôt que d'avoir à subir les pénalités d'évolutivité de l'utilisation de l'édition de tableaux de documents versionnés de Mongoose. Au moins, vous bénéficiez des avantages de la distribution des types basée sur les schémas de Mongoose pour les mises à jour !

3voto

lefnire Points 1389

I penser D'après notre expérience, la réponse à votre question est "oui". La Mangouste est no modulable pour des mises à jour rapides basées sur des tableaux.

Contexte

Nous rencontrons le même problème à HabitRPG . Après une récente augmentation du nombre d'utilisateurs (portant notre base de données à 6 gigaoctets), nous avons commencé à faire l'expérience d'un certain nombre de problèmes. VersionError pour de nombreuses mises à jour basées sur des tableaux ( Contexte de l'erreur de version ). ensureIndex({_id:1,__v1:1}) a aidé un peu, mais cela s'est estompé au fur et à mesure que d'autres utilisateurs se joignaient à l'initiative. Il me semble que Mongoose n'est en effet pas extensible pour les mises à jour basées sur des tableaux. Vous pouvez voir l'ensemble de notre procédure d'enquête ici .

Solution

Si vous pouvez vous permettre de passer d'un tableau à un objet, faites-le. Par exemple, comments: Schema.Types.Array => comments: Schema.Types.Mixed et trier par post.comments.{ID}.date ou même un manuel post.comments.{ID}.position si nécessaire.

Si vous êtes coincé avec des tableaux :

  1. db.collection.ensureIndex({_id:1,__v:1})
  2. Utilisez les méthodes décrites ci-dessus. Vous ne bénéficierez pas des crochets et des validations, mais il y a pire.

0voto

Aaron Dufour Points 6912

Je suggère fortement de regrouper ces tableaux dans de nouvelles collections. Par exemple, une collection Commentaires dans laquelle chaque document possède un numéro d'enregistrement pour indiquer sa place. Il s'agit d'une solution beaucoup plus évolutive.

Vous avez raison, les opérations sur les tableaux de Mongoose ne sont pas atomiques et ne s'adaptent donc pas bien.

0voto

MalcolmOcean Points 1288

J'ai pensé à une autre idée, dont je ne suis pas certain, mais qui semble valoir la peine d'être proposée : la suppression en douceur.

Mongoose est très préoccupé par les changements de structure des tableaux, car ils rendent les changements futurs ambigus. Mais si vous deviez simplement étiqueter un sous-document de commentaire avec la balise comment.deleted=true vous pourrez alors effectuer davantage d'opérations de ce type sans rencontrer de conflits. Vous pourriez alors avoir une tâche cron qui s'occupe de supprimer ces commentaires.

Oh, une autre idée est d'utiliser une sorte de cache mémoire, de sorte que si un enregistrement a été consulté/modifié au cours des dernières minutes, il est disponible sans avoir à l'extraire du serveur, ce qui signifie que deux requêtes arrivant en même temps vont modifier le même objet.

Note : Je ne suis pas sûr que soit de ces idées sont bonnes en général ou qu'elles résoudront votre problème, alors allez-y et éditez/commentez/downvotez si elles sont mauvaises :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X