2

I have the following user schema (where all distinct properties of different user types are consolidated):

var UserSchema = new mongoose.Schema({
  status: String,
  firstName: String,
  lastName: String,
  address: Object,
  email: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+@\S+\.\S+/, 'is invalid'], index: true},
  organization: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Organization' }],
  phone: {type: Number, unique: true, required: true, required: [true, "can't be blank"]}, 
  role: String, 
  hash: String,
  salt: String,
  deliverySchedule:  [{type: String, required: true}]

}

"Common" Schema (what all user types share in common):

var UserSchema = new mongoose.Schema({
  status: String,
  firstName: String,
  lastName: String,
  email: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+@\S+\.\S+/, 'is invalid'], index: true},
  phone: {type: Number, unique: true, required: true, required: [true, "can't be blank"]}, 
  role: String, 
  hash: String,
  salt: String
}

Role = "Customer":

  address: [{type: Object, required: true}]

Role = "DeliveryMan":

      deliverySchedule:  [{type: String, required: true}]
      organization: [{ type: mongoose.Schema.Types.ObjectId, required: true, 
ref: 'Organization' }],

Role = "Seller":

      organization: [{ type: mongoose.Schema.Types.ObjectId, required: true, 
ref: 'Organization' }],

I would like to add (and REQUIRE if possible) some fields to the "common" schema based on the user's role. However, I want to store them in the same collection.

How can I add a method to my models/Users.js to add properties to the schema based on "user.role"

1 Answer 1

3

Make require validation optional for each role dependent fields.

var UserSchema = new mongoose.Schema({
  status: String,
  firstName: String,
  lastName: String,
  email: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+@\S+\.\S+/, 'is invalid'], index: true},
  phone: {type: Number, unique: true, required: true, required: [true, "can't be blank"]}, 
  role: {type: String, enum: ['Customer', 'DeliveryMan', 'Seller'], required: true},
  address: {type: [Object],  required: isRequired("address")},
  deliverySchedule: {type: [String], required: isRequired("deliverySchedule")},
  organization: { type: [mongoose.Schema.Types.ObjectId], ref: 'Organization', required: isRequired("organization")},
  hash: String,
  salt: String
});

function isRequired(field){
    return function(){
        if(field == "address"){
            return this.role === "Customer"
        }
        else if(field == "deliverySchedule"){
            return this.role === "DeliveryMan"
        }
        else if(field == "organization"){
            return this.role === "Seller" || this.role === "DeliveryMan"
        }
    }
};
Sign up to request clarification or add additional context in comments.

6 Comments

This is more elegant than using discriminators. Thank you so much
I want to refactor inline functions to one function. How do I do that? function authorize(roles) { roles.forEach(role =>if (role === this.role) return true else return false }
for clarity, I meant to ask where can I place this function and how do I access it ?
You can certainly take the functions out but you can't merge them into one, because that one function will have no context to tell which field is calling it and which required should be set to true.
I see what you're saying, I keep getthing this.role as undefined. Can you show me the right practice of refactoring this? Thanks :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.