diff --git a/lib/model.js b/lib/model.js index 9f347ac41c..7a7277de9b 100644 --- a/lib/model.js +++ b/lib/model.js @@ -2619,6 +2619,10 @@ Model.create = async function create(doc, options) { delete options.aggregateErrors; // dont pass on the option to "$save" + if (options.session && !options.ordered && args.length > 1) { + throw new MongooseError('Cannot call `create()` with a session and multiple documents unless `ordered: true` is set'); + } + if (options.ordered) { for (let i = 0; i < args.length; i++) { try { diff --git a/test/docs/transactions.test.js b/test/docs/transactions.test.js index 2a63f07a98..e478ee1ec3 100644 --- a/test/docs/transactions.test.js +++ b/test/docs/transactions.test.js @@ -660,4 +660,44 @@ describe('transactions', function() { const { name } = await Test.findById(_id); assert.strictEqual(name, 'bar'); }); + + it('throws error if using `create()` with multiple docs in a transaction (gh-15091)', async function() { + const BookingSchema = new Schema({ + user: mongoose.Types.ObjectId, + slot: mongoose.Types.ObjectId, + bookingFor: String, + moreInfo: String + }); + + // Create models + const Booking = db.model('Test', BookingSchema); + + // Define a sample payload + const user = { userId: new mongoose.Types.ObjectId() }; + const payload = { + slotId: new mongoose.Types.ObjectId(), + data: [ + { bookingFor: 'Person A', moreInfo: 'Some info' }, + { bookingFor: 'Person B', moreInfo: 'Other info' } + ] + }; + + const session = await mongoose.startSession(); + session.startTransaction(); + + const bookingData = payload.data.map((obj) => ({ + user: user.userId, + slot: payload.slotId, + bookingFor: obj.bookingFor, + moreInfo: obj.moreInfo + })); + + await assert.rejects( + Booking.create(bookingData, { session }), + /Cannot call `create\(\)` with a session and multiple documents unless `ordered: true` is set/ + ); + + const bookings = await Booking.create(bookingData, { session, ordered: true }); + assert.equal(bookings.length, 2); + }); });