Change discriminator value/discriminated type in Mongoose

Viewed 3449

I've represented a class hierarchy in Mongoose via two models and a discriminator key (simple example):

var options = {discriminatorKey: 'kind'};
var UserSchema = new mongoose.Schema({
    username: {type: String, index: true},
    // some other fields
}, options);

// some  schema methods

var User = mongoose.model('User', UserSchema);
var PowerUserSchema = new mongoose.Schema({
    username: {type: String, index: true},
    // some other fields
    rank: {type: String}
}, options);
var PowerUser = User.discriminator('PowerUser', PowerUserSchema);

So far this works fine, however I ran into the situation, where I would like to "promote" a User to PowerUser. My initial idea was to set the "kind" property of a user and call save() on the instance, hoping that once the value is retrieved next time, the correct mongoose type will be returned:

var user = ... // retrieve user
user.kind = 'PowerUser';
user.save();
user = ... // retrieve user again

This doesn't appear to work, since the "kind" value is not saved to the instance. I came across this suggestion, which unfortunately did not update the discriminator value either.

My question now is: Am I even on the right track? Is updating the discriminator value even allowed for a situation like this, or should I better structure my data in a different way (e.g. use a single schema for both, with a "type" entry specifying what each instance is; this would have the effect that for the demotion case, no information is lost.)

Additionally, pro(de)moting a user should not break all the instances in my database where (Power)Users are referenced.

Thanks!

2 Answers

have you tried using findOneAndUpdate on the Model

 User.findOneAndUpdate({_id: _user._id}, {$set: {kind: "PowerUser"}, {new: true}, function (err, doc) {
        should.not.exist(err);
        should.exist(doc.kind);
        doc.kind.should.equal('PowerUser');

        done();
      });

you could use a static method like this in case you also need to remove properties already set. the value new: true is to get the new modified file and strict: false so you can unset values that dont already exist on UserSchema

changes = {kind: "PowerUser"}

UserSchema.statics.switchKind = function (id, changes, callBack) {
  const unset = {
    rank: undefined,
    someOtherField: undefined
  };
  return this.findOneAndUpdate({_id: id}, {$set: changes, $unset: unset}, {new: true, strict: false}, callBack);
};
Related