简体   繁体   中英

How to write a Mongoose model in ES6 / ES2015

I want to write my mongoose model in ES6. Basically replace module.exports and other ES5 things wherever possible. Here is what I have.

import mongoose from 'mongoose'

class Blacklist extends mongoose.Schema {
  constructor() {
    super({
      type: String,
      ip: String,
      details: String,
      reason: String
    })
  }
}

export default mongoose.model('Blacklist', Blacklist)

I see this error in the console.

if (!('pluralization' in schema.options)) schema.options.pluralization = this.options.pluralization;
                                 ^

TypeError: Cannot use 'in' operator to search for 'pluralization' in undefined

I'm not sure why you're attempting to use ES6 classes in this case. mongoose.Schema is a constructor to create new schemas. When you do

var Blacklist = mongoose.Schema({});

you are creating a new schema using that constructor. The constructor is designed so that behaves exactly like

var Blacklist = new mongoose.Schema({});

What you're alternative,

class Blacklist extends mongoose.Schema {

does is create a subclass of the schema class, but you never actually instantiate it anywhere

You'd need to do

export default mongoose.model('Blacklist', new Blacklist());

but I wouldn't really recommend it. There's nothing "more ES6y" about what you are doing. The previous code is perfectly reasonable and is the recommended API for Mongoose.

Mongoose can natively support es6 classes (since 4.7, and with no transpiler…).

Just write:

const mongoose = require('mongoose')
const { Model, Schema } = mongoose

const schema = new Schema({
  type: String,
  ip: String,
  details: String,
  reason: String,
})

class Tenant extends Model {}

module.exports = mongoose.model(Tenant, schema, 'tenant');

Why would you want to do it? mongoose.Schema is not expected to be used in this way. It doesn't use inheritance.

mongoose.Schema is a constructor that takes an object as the first parameter both in ES5 and ES6. No need for ES6 classes here.

Thus even with ES6 the proper way is to have:

const Blacklist = mongoose.Schema({
  type: String,
  ip: String,
  details: String,
  reason: String,
});

For those who find this searching around, the original question seems pretty valid to me. I'm using Babel transpiling ES6+ down to 5. My custom mongoose methods did not play well with my async/await code in my calling class. Notably this was null in my instance methods. Using the solution provided here, I was able to arrive at this solution that hopefully helps others searching around.

import mongoose from 'mongoose'

class Tenant extends mongoose.Schema {
  constructor() {
    const tenant = super({
      pg_id: Number,
      name: String,
      ...
    })

    tenant.methods.getAccountFields = this.getAccountFields
    tenant.methods.getCustomerTypes = this.getCustomerTypes
    tenant.methods.getContactFields = this.getContactFields
    ...
    tenant.methods.getModelFields = this.getModelFields

    return tenant
  }

  getAccountFields() {
    return this.getModelFields(this.account_fields_mapping)
  }

  getCustomerTypes() {
    //code
  }

  getContactFields() {
    //code
  }

  ...

  getModelFields(fields_mapping) {
    //code
  }
}

export default mongoose.model('Tenant', new Tenant)

To do things the ES6, class-like way, as the question states, I simply had to invoke the class with new in the exported mongoose.model function.

export default mongoose.model('Blacklist', new Blacklist)

This might be late to reply still, this may help someone who looking for this.

With ES6 Classes Schemas have a loadClass() method that you can use to create a Mongoose schema from an ES6 class:

  • ES6 class methods become Mongoose methods
  • ES6 class statics become Mongoose statics
  • ES6 getters and setters become Mongoose virtuals

Here's an example of using loadClass() to create a schema from an ES6 class:

class MyClass {
  myMethod() { return 42; }
  static myStatic() { return 42; }
  get myVirtual() { return 42; }
}

const schema = new mongoose.Schema();
schema.loadClass(MyClass);

console.log(schema.methods); // { myMethod: [Function: myMethod] }
console.log(schema.statics); // { myStatic: [Function: myStatic] }
console.log(schema.virtuals); // { myVirtual: VirtualType { ... } }

Reference: this is a sample code from mongoose documentation, for more details mongoose doc

I'm going to give a 2022 answer and how I do it with ES6. I think that using classes is not bringing benefit while creating a schema since it is just the definition or shape of the data.

// package.json
{
  ...
  "type": "module",
}
// root/models/users.model.js
import mongoose from 'mongoose'

const userSchema = new mongoose.Schema({ ... })

const UserModel = mongoose.model('Users', userSchema)
export { UserModel }
// root/routes/users.routes.js
import express from 'express'
import { UserModel } from '../models/users.model.js'

const userRouter = express.Router()

userRouter.post('/', async (req, res) => {
  const user = UserModel.create({ ...req.body })
  ...
}

I was having trouble myself using export default and module.exports but export {... } worked as expected.

This will work:

import mongoose from 'mongoose';

const { Schema } = mongoose;
const userSchema = new Schema({

  email: {
      type: String,
      required: true
  },
  firstName: {
      type: String,
  },
  lastName: {
      type: String
  },
  age: {
      type: Number
  }
});

export default mongoose.model('User', userSchema);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM