web-dev-qa-db-fra.com

Transactions Mongoose.js

Je sais que MongoDB ne prend pas en charge les transactions comme le font les bases de données relationnelles, mais je me demande toujours comment obtenir l'atomicité pour plusieurs opérations. Chassant sur le Web, je vois des gens mentionner Transactions sans transactions . En lisant les diapositives, je ne comprends toujours pas comment implémenter cela avec Mongoose.js.

Prenez cet extrait de code par exemple:

player.save(callback1);
story.save(callback2);

Comment implémenter callback1 et callback2 afin qu'ils réussissent ou échouent ensemble?

24

Si vous devez réellement effectuer des transactions sur plusieurs types de documents (dans des collections séparées), vous pouvez y parvenir avec un seul tableau contenant les actions à entreprendre.

db.actions.insert(
{ actions: [{collection: 'players', _id: 'p1', update: {$set : {name : 'bob'} } },
            {collection: 'stories', _id: 's1', update: {$set : {location: 'library'} } }], completed: false }, callback);

Cet insert est atomique, et tout est fait à la fois. Vous pouvez ensuite exécuter les commandes de la collection 'actions' et les marquer comme terminées ou les supprimer au fur et à mesure de leur exécution, en appelant votre rappel original une fois qu'elles sont toutes terminées. Cela ne fonctionne que si votre boucle de traitement des actions est la seule chose à mettre à jour la base de données. Bien sûr, vous devrez cesser d'utiliser de la mangouste, mais plus vite vous le ferez, mieux ce sera.

9
Will Shaver

Cette question est assez ancienne, mais pour tous ceux qui tombent sur cette page, vous pouvez utiliser fawn . C'est un paquet npm qui résout ce problème. Divulgation: je l'ai écrit

Supposons que vous ayez deux comptes bancaires, l’un appartenant à John Smith et l’autre à Broke Individual. Vous souhaitez transférer 20 $ de John Smith à Broke Individual. En supposant que toutes les paires nom/prénom soient uniques, cela pourrait ressembler à:

var Fawn = require("fawn");
var task = Fawn.Task()

//assuming "Accounts" is the Accounts collection 
task.update("Accounts", {firstName: "John", lastName: "Smith"}, {$inc: {balance: -20}})
  .update("Accounts", {firstName: "Broke", lastName: "Individual"}, {$inc: {balance: 20}})
  .run()
  .then(function(){
    //update is complete 
  })
  .catch(function(err){
    // Everything has been rolled back. 

    //log the error which caused the failure 
    console.log(err);
  });

Mise en garde: Les tâches Ne sont pas isolées (travaillent dessus), donc techniquement, il est possible que deux tâches récupèrent et éditent le même document simplement parce que c'est ainsi que MongoDB fonctionne. 

Il s’agit en réalité d’une implémentation générique de l’exemple de validation en deux phases sur le site du didacticiel: https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/

8
oj_1boss

Vous pouvez simuler une transaction en annulant manuellement les modifications chaque fois qu'une erreur se produit. Dans l'exemple ci-dessus, supprimez simplement le document enregistré en cas d'échec de l'autre.

Vous pouvez le faire facilement en utilisant Async:

    function rollback (doc, cb) {
      doc.remove(cb);
    }

    async.parallel([
          player.save.bind(player),
          story.save.bind(story),
      ],
      function (err, results) {
        if (err) {
          async.each(results, rollback, function () {
            console.log('Rollback done.');
          });
        } else {
          console.log('Done.');
        }
      });

De toute évidence, la restauration elle-même pourrait échouer. S'il s'agit d'une solution inacceptable, vous devrez probablement restructurer vos données ou choisir une autre base de données.

Note: J'ai discuté de cela en détail sur ce post .

6
jramoyo

Les transactions ne sont pas prises en charge dans MongoDB. Cependant, ils sont implémentables avec Protocole de validation en deux phases . Ici vous pouvez voir une recommandation officielle sur la façon de réaliser 2PC en MongoDB . Cette approche est assez universelle et peut être appliquée à différents scénarios tels que

  • documents de différentes collections (votre cas)
  • plus de 2 documents
  • actions personnalisées sur les documents
2
Sergiy Yeskov

Les transactions sont maintenant prises en charge dans Mongoose> = 5.2.0 et MongoDB> = 4.0.0 (avec jeux de réplicas)

https://mongoosejs.com/docs/transactions.html

1
João Otero