Reputation: 41
I am using mongoose in a Node & Mongoose application where I would like to use transactions. But get an unhandled exception. Any ideas on how to fix this?
Versions:
Node: 12.18.1.
Mongoose: 5.9.20
The code I am trying to execute:
const mongoose = require('mongoose');
const config = require('../config');
const database = config.database;
const uri = `mongodb+srv://${database.user}:${database.password}@${database.uri}`;
mongoose
.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: true,
useCreateIndex: true,
promiseLibrary: global.Promise
});
let parentSchema = new mongoose.Schema({
name: String
});
let childSchema = new mongoose.Schema({
parent: {
type: mongoose.Schema.Types.ObjectId,
ref: "Parent"
},
name: String,
requiredField: {
type: String,
required: true
}
});
let Parent = mongoose.model("Parent", parentSchema);
let Child = mongoose.model("Child", childSchema);
let session;
// Parent.startSession()
mongoose.startSession()
.then(_session => {
session = _session;
session.startTransaction();
let aParent = new Parent({ name: 'Parent 1'});
console.log('created parent');
return aParent.save({ session: session })
})
.then(_aParent => {
console.log('Parent saved');
let aChild = new Child({ parent: _aParent._id, name: 'Child 1' });
console.log('Child created');
return aChild.save({ session: session });
})
.then(_aChild => {
console.log('child saved')
session.commitTransaction();
})
.catch(_err => {
console.log('catch error');
session.abortTransaction();
})
.finally(() => {
session.endSession();
})
I am getting the following error:
throw new MongoError( ^
MongoError: Attempted illegal state transition from [TRANSACTION_ABORTED] to [TRANSACTION_ABORTED]
at Transaction.transition (C:\Users\chdejager\dev\node_modules\mongodb\lib\core\transactions.js:159:11)
at commandHandler (C:\Users\chdejager\dev\node_modules\mongodb\lib\core\sessions.js:508:27)
at C:\Users\chdejager\dev\node_modules\mongodb\lib\core\sessions.js:545:5
at cb (C:\Users\chdejager\dev\node_modules\mongodb\lib\core\sdam\topology.js:670:18)
at C:\Users\chdejager\dev\node_modules\mongodb\lib\cmap\connection_pool.js:354:13
at handleOperationResult (C:\Users\chdejager\dev\node_modules\mongodb\lib\core\sdam\server.js:493:5)
at _command (C:\Users\chdejager\dev\node_modules\mongodb\lib\core\wireprotocol\command.js:60:14)
at Object.command (C:\Users\chdejager\dev\node_modules\mongodb\lib\core\wireprotocol\command.js:28:5)
at Connection.command (C:\Users\chdejager\dev\node_modules\mongodb\lib\cmap\connection.js:164:8)
at C:\Users\chdejager\dev\node_modules\mongodb\lib\core\sdam\server.js:281:12
at Object.callback (C:\Users\chdejager\dev\node_modules\mongodb\lib\cmap\connection_pool.js:351:7)
at processWaitQueue (C:\Users\chdejager\dev\node_modules\mongodb\lib\cmap\connection_pool.js:474:23)
at ConnectionPool.checkIn (C:\Users\chdejager\dev\node_modules\mongodb\lib\cmap\connection_pool.js:267:5)
at C:\Users\chdejager\dev\node_modules\mongodb\lib\cmap\connection_pool.js:361:16
at handleOperationResult (C:\Users\chdejager\dev\node_modules\mongodb\lib\core\sdam\server.js:493:5)
at commandResponseHandler
(C:\Users\chdejager\dev\node_modules\mongodb\lib\core\wireprotocol\command.js:123:25)
Upvotes: 1
Views: 1920
Reputation: 41
So after a few iterations I have figured out that both session.abortTransaction()
and session.commitTransaction()
return a Promise
. The modified code works perfectly.
const mongoose = require('mongoose');
const config = require('../config');
const database = config.database;
const uri = `mongodb+srv://${database.user}:${database.password}@${database.uri}`;
mongoose
.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: true,
useCreateIndex: true,
promiseLibrary: global.Promise
});
let parentSchema = new mongoose.Schema({
name: String
});
let childSchema = new mongoose.Schema({
parent: {
type: mongoose.Schema.Types.ObjectId,
ref: "Parent"
},
name: String,
requiredField: {
type: String,
required: true
}
});
let Parent = mongoose.model("Parent", parentSchema);
let Child = mongoose.model("Child", childSchema);
let session;
mongoose.startSession()
.then(_session => {
session = _session;
session.startTransaction();
let aParent = new Parent({ name: 'Parent 1'});
console.log('created parent');
return aParent.save({ session: session })
})
.then(_aParent => {
console.log('Parent saved');
let aChild = new Child({ parent: _aParent._id, name: 'Child 1' });
console.log('Child created');
return aChild.save({ session: session });
})
.then(_aChild => {
console.log('child saved', session.transaction.state);
return session.commitTransaction();
})
.catch(_err => {
console.log(_err, session.transaction.state);
return session.abortTransaction();
})
.finally(() => {
console.log(session.transaction.state)
session.endSession();
mongoose.disconnect();
})
Upvotes: 1