Using `mongoose transactions` when saving message in two collections in mongodb

我是研究僧i 提交于 2021-02-11 14:54:36

问题


If the student sends a message to the teacher, the message is saved in the teachers and students collections. The same situation is when a teacher sends a message to the student, they are also save in the two collections teachers and students. How can I apply mongoose transaction in the following code so that the message is saved in two collections.I don' want a situation that the message will be saved in one collection and in the other collection will not be saved due to an error. I am asking for help and clues

const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();

//const app = express();

// Connect to our Database and handle an bad connections
module.exports.db = mongoose
    .createConnection(process.env.DATABASE, { 
        useNewUrlParser: true, 
        useFindAndModify: false,
        useUnifiedTopology: true, 
        useCreateIndex: true
    }
);




//controller
const db = require('./connection');

const session = db.startSession();
session.startTransaction();

module.exports.sendMessage = (req, res) => {
    
    let {sender, receiver, msg, role} = req.body;
    var hex = /[0-9A-Fa-f]{6}/g;

    sender = (hex.test(sender))? mongoose.Types.ObjectId(sender) : sender;
    receiver = (hex.test(receiver))? mongoose.Types.ObjectId(receiver) : receiver;
    console.log(sender, receiver, msg, 'send');

            if(role === 'tutor') {
                let teacherMessage =  new TeacherMessageSchema.TeacherMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    sender : sender
                })

                let studentMessage =  new TeacherMessageSchema.TeacherMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    receiver : receiver
                })
        
                db.db.collection('teachers').findOneAndUpdate( 
                    { _id : receiver },
                    { $push: { messages: teacherMessage } },
                    (err, updated) => {
                        console.log(updated, 'vvv');
        
                        updated.value.hashed_password = undefined;
                        updated.value.salt = undefined;
        
                        if(err) {
                            res.status(404).json(err);
                        }
        
                        if (updated) {
                            res.status(200).json(updated.value);

                            db.db.collection('students').findOneAndUpdate( 
                                { _id : sender },
                                { $push: { messages: studentMessage } },
                               
                            );
                        }
                    }, session(session)
                )
        
              
            }
        
        
            if(role === 'student') {
                let studentMessage =  new StudentMessageSchema.StudentMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    receiver : receiver
                })

                let teacherMessage =  new TeacherMessageSchema.TeacherMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    sender : sender
                })
        
               
        
                db.db.collection('students').findOneAndUpdate( 
                    { _id : sender },
                    { $push: { messages: studentMessage } },
                    (err, updated) => {
                        console.log(updated, 'sss');
            
                        updated.value.hashed_password = undefined;
                        updated.value.salt = undefined;
            
                        if(err) {
                            res.status(404).json(err);
                        }
            
                        if (updated) {
                            res.json(updated.value);
                            db.db.collection('teachers').findOneAndUpdate( 
                                { _id : receiver },
                                { $push: { messages: teacherMessage } },
                               
                            )
                        }
                    }, 
                ), session(session)
            }
}

Logged variable db

{
  db: NativeConnection {
    base: Mongoose {
      connections: [Array],
      models: [Object],
      modelSchemas: [Object],
      options: [Object],
      _pluralize: [Function: pluralize],
      plugins: [Array]
    },
    collections: {},
    models: {},
    config: { autoIndex: true },
    replica: false,
    options: null,
    otherDbs: [],
    relatedDbs: {},
    states: [Object: null prototype] {
      '0': 'disconnected',
      '1': 'connected',
      '2': 'connecting',
      '3': 'disconnecting',
      '99': 'uninitialized',
      disconnected: 0,
      connected: 1,
      connecting: 2,
      disconnecting: 3,
      uninitialized: 99
    },
    _readyState: 1,
    _closeCalled: false,
    _hasOpened: true,
    _listening: false,
    _connectionOptions: {
      useNewUrlParser: true,
      useFindAndModify: false,
      useUnifiedTopology: true,
      useCreateIndex: true,
      promiseLibrary: [Function: Promise]
    },
    client: MongoClient {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      s: [Object],
      topology: [ReplSet],
      [Symbol(kCapture)]: false
    },
    name: null,
    '$initialConnection': Promise { [Circular] },
    db: Db {
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      s: [Object],
      serverConfig: [Getter],
      bufferMaxEntries: [Getter],
      databaseName: [Getter],
      [Symbol(kCapture)]: false
    }
  }
}

回答1:


I have added in the code Anytime there is an error:

await session.abortTransaction();

Otherwise (happy path) commit the changes.

await session.commitTransaction();

Abort and commit are Promise base functions, so I have changed the functions where they were used as async.

const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();

//const app = express();

// Connect to our Database and handle an bad connections
module.exports.db = mongoose
    .createConnection(process.env.DATABASE, { 
        useNewUrlParser: true, 
        useFindAndModify: false,
        useUnifiedTopology: true, 
        useCreateIndex: true
    }
);




//controller
const db = require('./connection');



module.exports.sendMessage = async (req, res) => {
    
    const session = await db.startSession();
    session.startTransaction();

    let {sender, receiver, msg, role} = req.body;
    var hex = /[0-9A-Fa-f]{6}/g;

    sender = (hex.test(sender))? mongoose.Types.ObjectId(sender) : sender;
    receiver = (hex.test(receiver))? mongoose.Types.ObjectId(receiver) : receiver;
    console.log(sender, receiver, msg, 'send');

            if(role === 'tutor') {
                let teacherMessage =  new TeacherMessageSchema.TeacherMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    sender : sender
                })

                let studentMessage =  new TeacherMessageSchema.TeacherMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    receiver : receiver
                })
        
                db.db.collection('teachers').findOneAndUpdate( 
                    { _id : receiver },
                    { $push: { messages: teacherMessage } },
                    async (err, updated) => {
                        console.log(updated, 'vvv');
        
                        updated.value.hashed_password = undefined;
                        updated.value.salt = undefined;
        
                        if(err) {
                            await session.abortTransaction();
                            res.status(404).json(err);
                            return
                        }
        
                        if (updated) {
                            res.status(200).json(updated.value);

                            db.db.collection('students').findOneAndUpdate( 
                                { _id : sender },
                                { $push: { messages: studentMessage } },
                               
                            );
                        }
                    }, session(session)
                )
        
              
            }
        
        
            if(role === 'student') {
                let studentMessage =  new StudentMessageSchema.StudentMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    receiver : receiver
                })

                let teacherMessage =  new TeacherMessageSchema.TeacherMessageSchema({
                    contentInfo : {
                        msg : msg
                    },
                    sender : sender
                })
        
               
        
                db.db.collection('students').findOneAndUpdate( 
                    { _id : sender },
                    { $push: { messages: studentMessage } },
                    async (err, updated) => {
                        console.log(updated, 'sss');
            
                        updated.value.hashed_password = undefined;
                        updated.value.salt = undefined;
            
                        if(err) {
                            await session.abortTransaction();
                            res.status(404).json(err);
                            return;
                        }
            
                        if (updated) {
                            res.json(updated.value);
                            db.db.collection('teachers').findOneAndUpdate( 
                                { _id : receiver },
                                { $push: { messages: teacherMessage } },
                               
                            )
                        }
                    }, 
                    session(session)
                )
            }

            await session.commitTransaction();
}


来源:https://stackoverflow.com/questions/65765198/using-mongoose-transactions-when-saving-message-in-two-collections-in-mongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!