Skip to content
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

How to retrieve current logged user from mongoose middlewares? #14530

Closed
1 task done
nikzanda opened this issue Apr 22, 2024 · 7 comments
Closed
1 task done

How to retrieve current logged user from mongoose middlewares? #14530

nikzanda opened this issue Apr 22, 2024 · 7 comments
Labels
help wanted help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary Stale

Comments

@nikzanda
Copy link

nikzanda commented Apr 22, 2024

Prerequisites

  • 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).

image

@nikzanda nikzanda added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Apr 22, 2024
@humblewolfstudio
Copy link

You should have the userId somewhere in the session right? Are you authenticating the users that request that endpoint?

@nikzanda
Copy link
Author

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.

@vkarpov15
Copy link
Collaborator

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?

@nikzanda
Copy link
Author

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?

@vkarpov15
Copy link
Collaborator

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?

Copy link

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

@github-actions github-actions bot added the Stale label May 20, 2024
@nikzanda
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary Stale
Projects
None yet
Development

No branches or pull requests

3 participants