Mongoose/MongoDB updateOne重复执行问题排查求助
Hey there! Let's break down why your User.updateOne is running twice while Snapshot.updateOne behaves as expected, and fix this issue step by step.
First, Let's Spot the Red Flag in Your Code
Looking at your User.updateOne call, you're mixing callbacks and Promises in the same method invocation:
User.updateOne( { _id: args.id }, { $inc: { 'currency.cs': 1 } }, (err, res) => { if (err) console.log(err); } ).then(user => { console.log('End increment query'); return 'It worked'; });
While modern Mongoose versions handle this in most cases, this hybrid approach can lead to unexpected execution paths—especially if your Mongoose version has edge cases around dual callback/Promise support. The Snapshot.updateOne call uses only Promises and works fine, which is a strong clue here.
Next, Check for Duplicate Event Listeners
The most likely culprit here is that your upgrade-stat socket event listener is being bound twice. This usually happens if:
- The code block containing
socket.on('upgrade-stat', ...)runs multiple times (e.g., inside a Passport deserialization callback that fires twice, or in a connection handler that re-runs for the same socket). - Your Passport session setup is triggering a re-initialization of the socket connection, leading to duplicate listener bindings.
Fixes to Try
1. Clean Up the Callback/Promise Hybrid
First, standardize on Promises for consistency (and eliminate any edge cases from mixed usage):
socket.on('upgrade-stat', data => { const userId = socket.handshake.session.passport.user; console.log('Snapshot Start'); // Snapshot update (unchanged, Promise-only) Snapshot.updateOne( { userid: userId }, { $inc: { 'stats.str': 1 } } ).then((res) => { console.log('Snapshot done'); }); console.log('Start increment query'); // User update: Promise-only, no callback User.updateOne( { _id: userId }, { $inc: { 'currency.cs': 1 } } ) .then(user => { console.log('End increment query'); return 'It worked'; }) .catch(err => console.error('User update error:', err)); });
2. Prevent Duplicate Event Bindings
Ensure your listener is only attached once per socket. You can either:
- Use
socket.onceinstead ofsocket.onif the event should only fire once per connection (though this might not fit your use case). - Explicitly remove existing listeners before adding a new one:
// Remove any existing listeners first, then bind the new one socket.off('upgrade-stat').on('upgrade-stat', data => { // Your updated handler logic here });
3. Audit Passport Deserialization
Double-check where you're binding the upgrade-stat listener. If it's inside a Passport deserialization callback or a function that runs on session refresh, that could be causing the listener to be added multiple times. Add console logs to track how often the listener binding code runs—if it fires twice, that's your issue.
Verify the Fix
After making these changes, re-enable Mongoose debugging. You should see only one users.updateOne entry in the logs, matching the single snapshots.updateOne entry.
内容的提问来源于stack exchange,提问作者William

