web-dev-qa-db-fra.com

Transactions Mongodb 4.0 avec Mongoose et Node Js, Express

Je développe une application où j'utilise MongoDB comme base de données avec Nodejs + Express en couche application, j'ai deux collections, à savoir

  1. utilisateurs
  2. transactions

Ici, je dois mettre à jour le portefeuille de milliers d'utilisateurs avec un certain montant et en cas de succès, créer un nouveau document avec des informations connexes pour chaque transaction, voici mon code:

 userModel.update({_id : ObjectId(userId)}, {$inc : {wallet : 500}}, function (err, creditInfo) {
    if(err){
        console.log(err);                            
    }
    if(creditInfo.nModified > 0) {
        newTransModel = new transModel({
            usersId: ObjectId(userId),            
            amount: winAmt,         
            type: 'credit',           
        }); 
        newTransModel.save(function (err, doc) {
            if(err){
                Cb(err); 
            }
        });
    }                            
});

mais cette solution n'est pas atomic il y a toujours une possibilité de mise à jour du portefeuille utilisateur avec le montant mais la transaction associée n'est pas créée dans la collecte des transactions entraînant une perte financière.

J'ai entendu dire que récemment MongoDB a ajouté Transactions support dans son 4.0 version, J'ai lu les documents MongoDB mais je n'ai pas réussi à l'implémenter avec succès avec mongoose dans Node.js , quelqu'un peut-il me dire comment cela le code ci-dessus soit réimplémenté en utilisant la dernière fonctionnalité Transactions de MongoDB qui a ces fonctions

Session.startTransaction()
Session.abortTransaction()
Session.commitTransaction()

Documents MongoDB: Cliquez ici

11
Gaurav Kumar

avec mangouste dans Node.js, quelqu'un peut-il me dire comment ce code ci-dessus peut être réimplémenté en utilisant la dernière fonctionnalité Transactions

Pour utiliser transactions multi-documents MongoDB support dans mongoose vous avez besoin d'une version supérieure à v5.2. Par exemple:

npm install [email protected]

Les méthodes transactionnelles Mongoose renvoient une promesse plutôt qu'une session qui nécessiterait d'utiliser await. Voir:

Par exemple, en modifiant l'exemple de la ressource ci-dessus et votre exemple, vous pouvez essayer:

const User = mongoose.model('Users', new mongoose.Schema({
  userId: String, wallet: Number
}));
const Transaction = mongoose.model('Transactions', new mongoose.Schema({
  userId: ObjectId, amount: Number, type: String
}));

await updateWallet(userId, 500);

async function updateWallet(userId, amount) {
  const session = await User.startSession();
  session.startTransaction();
  try {
    const opts = { session };
    const A = await User.findOneAndUpdate(
                    { _id: userId }, { $inc: { wallet: amount } }, opts);

    const B = await Transaction(
                    { usersId: userId, amount: amount, type: "credit" })
                    .save(opts);

    await session.commitTransaction();
    session.endSession();
    return true;
  } catch (error) {
    // If an error occurred, abort the whole transaction and
    // undo any changes that might have happened
    await session.abortTransaction();
    session.endSession();
    throw error; 
  }
}

n'est pas atomique, il existe toujours une possibilité de mise à jour du portefeuille utilisateur avec le montant mais la transaction associée n'est pas créée dans la collecte des transactions entraînant une perte financière

Vous devriez également envisager de changer votre MongoDB modèles de données . Surtout si les deux collections sont naturellement liées. Voir aussi Données de modèle pour les opérations atomiques pour plus d'informations.

Un exemple de modèle que vous pouvez essayer est Event Sourcing model. Créez d'abord une entrée de transaction en tant qu'événement, puis recalculez le solde du portefeuille de l'utilisateur à l'aide de agrégation .

Par exemple:

{tranId: 1001, fromUser:800, toUser:99, amount:300, time: Date(..)}
{tranId: 1002, fromUser:77, toUser:99, amount:100, time: Date(..)}

Introduisez ensuite un processus pour calculer le montant pour chaque utilisateur par période en tant que cache en fonction des besoins (c'est-à-dire toutes les 6 heures). Vous pouvez afficher le solde du portefeuille de l'utilisateur actuel en ajoutant:

  • Le dernier montant mis en cache pour l'utilisateur
  • Toutes les transactions pour l'utilisateur se produisent depuis le dernier montant mis en cache. soit il y a 0 à 6 heures.
15
Wan Bachtiar