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

Fail to register global plugin #7723

Closed
LouisGirones opened this issue Apr 18, 2019 · 9 comments
Closed

Fail to register global plugin #7723

LouisGirones opened this issue Apr 18, 2019 · 9 comments
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation
Milestone

Comments

@LouisGirones
Copy link

*Before creating an issue please make sure you are using the latest version of mongoose

Do you want to request a feature or report a bug?

Report a bug

What is the current behavior?

Using a plugin in every model works, but using the plugin globally aka mongoose.plugin(myPlugin) does not

If the current behavior is a bug, please provide the steps to reproduce.

I am linking this issue since it seems kinda related :
#7042 (comment)

I've created a very basic plugin :

import mongoose from 'mongoose'

const fieldsPlugin: any = (
    schema: mongoose.Schema,
    _option: mongoose.SchemaOptions
    ): void => {
    schema.set('toJSON', {
        transform: (_doc: mongoose.Document, ret: mongoose.Document): void => {
            ret.id = ret._id
            delete ret._id
            delete ret.__v
        },
    })
}

export default fieldsPlugin

UserSchema.plugin(myPlugin) myPlugin is added to the UserSchema as it should
mongoose.plugin(myPlugin) myPlugin should be added for all schema

However the mongoose.plugin(myPlugin) does not works while adding UserSchema.plugin(myPlugin) works

What is the expected behavior?

Using mongoose.plugin(myPlugin) should have the same results as adding myModel.plugin(myPlugin) in every of my schema.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.

node version: 11
mongodb version : 4
mongoose version : 5.5.2

@TrejGun
Copy link
Contributor

TrejGun commented Apr 22, 2019

this is what you can do

mongoose.plugin(function(schema) {
  const localTransform = (schema.get("toJSON") || {transform: (doc, ret) => ret}).transform;
  schema.set("toJSON", {
    transform(doc, ret) {
      return globalTransform(localTransform(doc, ret));
    },
  });
});

@LouisGirones
Copy link
Author

LouisGirones commented Apr 22, 2019

Hello,

Thank you very much for your help, sadly the global plugin still does not works for me with the code you posted.
Also with your code I am haing an error Cannot find name 'globalTransform'. Did you mean 'localTransform'? it might be why it does not works for me maybe

@vkarpov15
Copy link
Collaborator

@LouisGirones can you please show how you're defining your user model? Global plugins aren't applied until you call mongoose.model() or connection.model().

@vkarpov15 vkarpov15 added the needs clarification This issue doesn't have enough information to be actionable. Close after 14 days of inactivity label Apr 23, 2019
@LouisGirones
Copy link
Author

Yes sure, I have this file for starting the node server in the root folder (app.ts) :

/**
 * Main application file
 */
import express from 'express'
import http from 'http'
import mongoose from 'mongoose'
import config from './config/environment'
import expressConfig from './config/express'
import routesConfig from './routes'

// Connect to database
mongoose.connect(config.mongo.uri, config.mongo.options)

// Setup server
const app: express.Application = express()
const server: http.Server = http.createServer(app)

expressConfig(app)
routesConfig(app)

// Start server
server.listen(config.port, () => {
    console.log(`Express server listening on port ${config.port}, in ${app.get('env')} mode`)
})

// Expose app
export default app

./routes code :

/**
 * Main application routes
 */

import express from 'express'
import httpStatus from 'http-status-codes'
import user from './api/user'
import config from './config/environment'

const routes = (app: express.Application): void => {
    // API routes
    app.use(`${config.apiVersion}user`, user)

    // All other routes should 404
    app.route('/*')
        .get((_req: express.Request, res: express.Response) => {
            res.sendStatus(httpStatus.NOT_FOUND)
        })
}

export default routes

And in ./api/user I have three files user.model.ts :

import mongoose from 'mongoose'
// import fieldsPlugin from '../../plugin/fields' does not work when using mongoose.plugin()

const userSchema: mongoose.Schema = new mongoose.Schema({
    login: {
        required: true,
        type: String,
        unique: 'Le nom d\'utilisateur \`{VALUE}\` est déjà utilisé',
    },
    mail: {
        required: true,
        type: String,
        unique: 'Le mail \`{VALUE}\` est déjà utilisé',
    },
}, { timestamps: true })


// userSchema.plugin(fieldsPlugin)

export const User: mongoose.Model<IUser> = mongoose.model<IUser>('User', userSchema)

user.controller.ts :

import { Request, Response } from 'express'
import { User } from './user.model'

class UserController {

    public get = async (
        _req: Request,
        res: Response
    ): Promise<Response> => {
        const users = await User.find()
        return res.send(users)
    }
}

export default new UserController()

and index.ts :


import { Router } from 'express'
import UserController from './user.controller'

const router: Router = Router()

router.get('/:userId', UserController.get)

export default router

So I would think that calling mongoose.plugin(myPlugin) after routesConfig(app) (in app.ts) would works since mongoose.model() is indirectly called in the routes.ts file when doing app.use(${config.apiVersion}user, user)

So I might have to change where I call mongoose.model()

@vkarpov15
Copy link
Collaborator

@LouisGirones you need to call mongoose.plugin(fieldsPlugin) before calling mongoose.model(). So in this case, you would need to call mongoose.plugin(fieldsPlugin) before doing import routesConfig from './routes' because that compiles the model. In general, it is best practice to export schemas, not models, because once you compile a model, you can no longer modify the schema.

@hamidjafari
Copy link

@LouisGirones you need to call mongoose.plugin(fieldsPlugin) before calling mongoose.model(). So in this case, you would need to call mongoose.plugin(fieldsPlugin) before doing import routesConfig from './routes' because that compiles the model. In general, it is best practice to export schemas, not models, because once you compile a model, you can no longer modify the schema.

thanks for your great point
but using ref in schema require model . that's the problem with exporting schema instead of model.

@vkarpov15
Copy link
Collaborator

ref can also be a string model name, doesn't necessarily need to be a model class.

@Eunovo
Copy link

Eunovo commented Aug 23, 2020

@LouisGirones you need to call mongoose.plugin(fieldsPlugin) before calling mongoose.model(). So in this case, you would need to call mongoose.plugin(fieldsPlugin) before doing import routesConfig from './routes' because that compiles the model. In general, it is best practice to export schemas, not models, because once you compile a model, you can no longer modify the schema.

@vkarpov15

I fell into this trap and this comment cleared my issue. Is this fact mentioned anywhere in the mongoose docs? I feel like I could have saved myself from stress if I had seen this earlier.

@vkarpov15 vkarpov15 reopened this Aug 26, 2020
@vkarpov15 vkarpov15 added this to the 5.10.2 milestone Aug 26, 2020
@vkarpov15 vkarpov15 added docs This issue is due to a mistake or omission in the mongoosejs.com documentation and removed needs clarification This issue doesn't have enough information to be actionable. Close after 14 days of inactivity labels Aug 26, 2020
@vkarpov15
Copy link
Collaborator

@Eunovo we made a point of this in the middleware docs, but we should also make a note in the plugins docs because many plugins rely heavily on middleware.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation
Projects
None yet
Development

No branches or pull requests

5 participants