mongoose
mongoose copied to clipboard
How to retrieve current logged user from mongoose middlewares?
Prerequisites
- [x] I have written a descriptive issue title
Mongoose version
8.3.2
Node.js version
20.10.0
MongoDB version
6.0.2
Operating system
macOS
Operating system version (i.e. 20.04, 11.3, 10)
14.3.1
Issue
I need to retrieve the user who made a request to my webApp endpoint in which I run an update on a mongoose model.
I want to use the user's id in a pre('save', ...)
in order to save an activity log, or maybe in order to auto update a lastModifiedBy
field in each of my collections (least preferred option, and I don't want to set it manually using model.set
function).
You should have the userId somewhere in the session right? Are you authenticating the users that request that endpoint?
You should have the userId somewhere in the session right? Are you authenticating the users that request that endpoint?
Yes, I have an express web application and users log in the app by JWT authentication, so I have the userId available in every method in the req variable.
session
is typically used for MongoDB transactions.
The easiest way to pass data to pre('save')
middleware is by adding the data to the document's $locals
property. That's a property on the document that Mongoose doesn't store in MongoDB and is used for storing ephemeral data for getters, virtuals, middleware, etc.
// In Express route handler:
doc.$locals.userId = req.userId;
// In schema definition:
schema.pre('save', function() {
this.$locals.userId; // from `req.userId`
});
Does this help?
session
is typically used for MongoDB transactions.The easiest way to pass data to
pre('save')
middleware is by adding the data to the document's$locals
property. That's a property on the document that Mongoose doesn't store in MongoDB and is used for storing ephemeral data for getters, virtuals, middleware, etc.// In Express route handler: doc.$locals.userId = req.userId; // In schema definition: schema.pre('save', function() { this.$locals.userId; // from `req.userId` });
Does this help?
That's exactly what I was looking for, thanks. The only downside is that I have to set it manually before every save directly on the document: the optimal solution would be to set it automatically one time for every db operation at the beginning of a user's request, for example directly in an express middleware. Is there a way to do so? Moreover, using $locals does not work with all the functions performed directly on the database eg. updateMany, deleteMany, findOneAndUpdate, updateOne, etc... because there's the need to retrieve the document before. Any ideas on how to manage this use case?
To automatically make userId accessible from middleware without explicitly passing it every time, you'd something like async local storage.
For queries, you can set the userId as an option and then access it from middleware:
// In Express route handler:
await TestModel.findOne().setOptions({ userId });
// In schema definition:
schema.pre('findOne', function() {
this.options.userId; // from `req.userId`
});
Are you trying to use Mongoose middleware to implement authorization?
This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days
To automatically make userId accessible from middleware without explicitly passing it every time, you'd something like async local storage.
For queries, you can set the userId as an option and then access it from middleware:
// In Express route handler: await TestModel.findOne().setOptions({ userId }); // In schema definition: schema.pre('findOne', function() { this.options.userId; // from `req.userId` });
Are you trying to use Mongoose middleware to implement authorization?
Thanks, I will try with async local storage.
No, I'm not implementing authorization inside Mongoose middleware, I want to store log for each user operations in every model.