Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose, set default to null and unique

I am trying to create a User Schema that has a key of 'facebookid', which is a unique value that is only given when a user signs up with facebook, but not when a user signs up through google or locally. When a user signs up locally, the facebookid is set to null as a default. However I am getting the error: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index: db22.users.$facebookid_1 dup key: { : null }'

Here is the Schema:

let UserSchema = new Schema({
    facebookid: {
        type: String,
        required: false, // only required for facebook users
        unique: true,
        default: null
    },
    // more details + keys below ...
})

So how can I allow duplicate entries for the key facebookid if the value is null if I also want entries to be unique?

i.e I don't want to see two similar String entries:
not okay:

* User: {_id: 123, facebookid: '4325',username:'joe'}
* User: {_id: 432, facebookid: '4325', username: 'pat'}

okay:

* User: {_id: 123, facebookid: null,username:'joe'}
* User: {_id: 432, facebookid: null, username: 'pat'}
like image 595
mdash1 Avatar asked Nov 21 '17 07:11

mdash1


3 Answers

You can use partialFilterExpressions:

facebookid: {
  type: String,
  required: false, // only required for facebook users
  index: {
    unique: true,
    partialFilterExpression: { facebookid: { $type: 'string' } },
  },
  default: null,
 }

This allows null to be used several times.

Remember to restart Mongoose and all that after changing the unique constraints. See this question if you haven't already.

like image 90
Mika Sundland Avatar answered Nov 05 '22 20:11

Mika Sundland


Thanks @Mikas!

Extra bonus - you can refer nested keys as follows: "key1.key2".
Unfortunately, $ne is not supported (yet?), so you cannot use simply: $ne: null

    key1: {
        key2: {
            type: String,
            index: {
                unique: true,
                partialFilterExpression: {
                    "key1.key2": {
                        // $ne: null,
                        $type: Schema.Types.String
                    }
                },

            },
            default: null
        }
like image 3
barakbd Avatar answered Nov 05 '22 20:11

barakbd


For that situation you should not use unique: true in schema but you have to check facebookid is already exist or not so you can add validation for facebookid using schemaName.path and check uniqueness. like bellow.

let UserSchema = new Schema({
    facebookid: {
        type: String,
        required: false,
        default: null
    },
    // more details + keys below ...
})

UserSchema.path('facebookid').validate(function(value, next){
  if(!value) {
    return next();
  }
  // I assueme your model name is User
  mongoose.models['User'].findOne({facebookid: value }, function(err, found){
    if(err){
      return next(false);
    }

    if(found && found.facebookid){
      return next(false, "Already exist this facebook ID");
    }else{
      return next();
    }
  });

});
like image 2
Shaishab Roy Avatar answered Nov 05 '22 20:11

Shaishab Roy