-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG.v5.2.1] ClientSession cannot be serialized to BSON - Sessions #6663
Comments
I haven't used sessions at all yet, so I'm really not sure if this should work or not. I was able to create a complete repro script that demonstrates the outcome based on some assumptions about @GregoryNEUT's code sample. 6663.js#!/usr/bin/env node --no-deprecation
'use strict';
const { ATLASSRV } = require('/Users/lineus/.env');
const mongoose = require('mongoose');
mongoose.connect(ATLASSRV.replace(/test/, 'gh-6663'));
const conn = mongoose.connection;
const Schema = mongoose.Schema;
const schemaA = new Schema({
name: String
});
const schemaB = new Schema({
name: String
});
const A = mongoose.model('A', schemaA);
const B = mongoose.model('B', schemaB);
const a = new A({ name: 'Andrew' });
const b = new B({ name: 'Billy' });
async function run() {
await conn.dropDatabase();
await a.save();
await b.save();
const session = await A.startSession();
const foundA = await A.findOne({}, { session });
await B.findOneAndUpdate({}, { name: foundA.name }, { session });
await session.commitTransaction();
session.endSession();
let newB = await B.findOne({});
console.log(`hello from ${newB.name}`);
return conn.close();
}
run().catch(console.error); Output:
something about creating the session on the first model, and passing it to a query on the second model feels wrong |
This is a common gotcha that we should add docs for, but your issue is that the 2nd arg to |
@vkarpov15 LOL 🤕 I can't believe I missed that. I had to make a couple of adjustments to my example that were wrong beyond the missing projection. In case it might help someone in the future here is the working code: 6663.js#!/usr/bin/env node --no-deprecation
'use strict';
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017,localhost:27018,localhost:27019/gh-6663?replicaSet=rs');
const conn = mongoose.connection;
const Schema = mongoose.Schema;
const schemaA = new Schema({
name: String
});
const schemaB = new Schema({
name: String
});
const A = mongoose.model('A', schemaA);
const B = mongoose.model('B', schemaB);
const a = new A({ name: 'Andrew' });
const b = new B({ name: 'Billy' });
async function run() {
await conn.dropDatabase();
await a.save();
await b.save();
const session = await A.startSession();
await session.startTransaction();
const foundA = await A.findOne({}, {}, { session });
await B.findOneAndUpdate({}, { name: foundA.name }, { session });
await session.commitTransaction();
session.endSession();
let newB = await B.findOne({});
console.log(`hello from ${newB.name}`);
return conn.close();
}
run().catch(console.error); Output:
|
It is a real bug in debug environment. mongoose.set('debug', true); |
const {MongoClient} = require('mongodb');
const uri = 'mongodb://localhost:27017,localhost:27018,localhost:27019/test-mongodb';
MongoClient.connect(uri, {useNewUrlParser: true, replicaSet: 'rs'}).then(async (client) => {
// console.log(client);
const db = client.db();
await db.dropDatabase();
await db.collection('Account').insertMany([
{name: 'A', balance: 5},
{name: 'B', balance: 10}
]);
await transfer('A', 'B', 4); // Success
try {
await transfer('A', 'B', 6);
} catch (error) {
console.log(error);
}
// The actual transfer logic
async function transfer(from, to, amount) {
const session = client.startSession();
session.startTransaction();
try {
const opts = {session, returnOriginal: false};
const B = await db.collection('Account').findOneAndUpdate({name: to}, {$inc: {balance: amount}}, opts).then(res => res.value);
const A = await db.collection('Account').findOneAndUpdate({name: from}, {$inc: {balance: -amount}}, opts).then(res => res.value);
if (A.balance < 0) {
// If A would have negative balance, fail and abort the transaction
// `session.abortTransaction()` will undo the above `findOneAndUpdate()`
throw new Error('Insufficient funds: ' + (A.balance + amount));
}
await session.commitTransaction();
session.endSession();
return {from: A, to: B};
} 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; // Rethrow so calling function sees error
}
}
}).catch(console.log);
@vkarpov15 your example worked |
Hello; trying to use simple transaction case as described in the documentation; I'm getting an error
My code look like :
Versions I use :
Thanks
The text was updated successfully, but these errors were encountered: