Friday 2 June 2017

Mongoose upsert doesn't set defaults for Schema.types.mixed properties, setDefaultsOnInsert is true

I'm using an upsert function to serialize users with my backend. I'm using Mongoose's "findOneAndUpdate" with "upsert: true" and "setDefaultsOnInsert: true" set, so that all default values defined in my Schema ought to be used for all parameters that I don't pass to the upsert.

This is my upsert:

let serialize = (params, cb) => {

  User.findOneAndUpdate({"fbId" : params.fbId}, params, { upsert: true, setDefaultsOnInsert: true, new: true }, (err, doc) => {

    if (err) {
      //winston.log
      return cb (ErrorTypes.serverError(), null);
    }
    else if (doc) {
      return cb(null, doc);
    }
    else {
      return cb(ErrorTypes.serverError(), null);
    }

  });

}

For this schema:

const userSchema = new Mongoose.Schema({

  fbId: {
    type: String,
    index: true,
    required: "Users must have a facebook ID.",
    maxlength: 40
  },
  firstName: {
    type: String,
    required: "Users must have a name.",
    maxlength: 40
  },
  lastName: {
    type: String,
    required: "Users must have a name.",
    maxlength: 40
  },
  gender: {
    type: String,
    required: "Users must have a gender",
    default: "Unknown"
  },
  ageRange: {
    type: String,
    default: "Unknown",
    maxlength: 25
  },
  pictureUrl: {
    type: String,
    required: "Users must have a profile picture."
  },
  dateJoined: {
    type: Number,
    required: "Users must have a joined date.", 
    default: date.getTime()
  },
  pushId: String,
  bookmarks: [{
    item: {
      type: Mongoose.Schema.Types.ObjectId,
      ref: 'Item',
      required: "An item id is required to create a bookmark."
    },
    lastOfferMade: Number,
    timeOfferMade: Number,
  }], default: [], 
  offersInCategory: {
      type: Object,
      validate: object => { 
        let allowedKeys = ['Furniture', 'Household', 'Electronics', 'Other'];
        let correctKeys = Object.keys(object).every(key => allowedKeys.includes(key)); 

        let min = 0;
        let correctValues = Object.values(object).every(value => value >= min); 

        return correctKeys && correctValues;
  }
  }, default: {
    'Furniture': 0, 
    'Household': 0, 
    'Electronics': 0,
    'Other': 0
  },
  rejectionsInCategory: {
      type: Object,
      validate: object => { 
        let allowedKeys = ['Furniture', 'Household', 'Electronics', 'Other'];
        let correctKeys = Object.keys(object).every(key => allowedKeys.includes(key)); 

        let min = 0;
        let correctValues = Object.values(object).every(value => value >= min ); 

        return correctKeys && correctValues; 
      }
  }, default: {
    'Furniture': 0, 
    'Household': 0, 
    'Electronics': 0,
    'Other': 0
  }, 
  blockedUsers: [{
    userId: String,
    blockedOn: Number
  }], default: [],
  blockedBy: [{
    userId: String,
    blockedOn: Number
  }], default: [],
  hasSeenWalkThrough: { type: Boolean, default: false },
  hasBookmarkedItem: { type: Boolean, default: false },
  hasSeenSearchPrompt: { type: Boolean, default: false }

});

Passing in these parameters:

var upsertNewParams = {
    fbId: "newUpsertFbId",
    firstName: "New upsert - User", 
    lastName: "Test Last Name - User", 
    gender: "Male", 
    ageRange: "18-22",
    pictureUrl: "url", 
    pushId: "12345"
}

My upsert function returns this document:

{ _id: 5931b0efbeadf32d858a7578,
  fbId: 'newUpsertFbId',
  __v: 0,
  firstName: 'New upsert - User',
  lastName: 'Test Last Name - User',
  pictureUrl: 'url',
  pushId: '12345',
  hasSeenSearchPrompt: false,
  hasBookmarkedItem: false,
  hasSeenWalkThrough: false,
  blockedBy: [],
  blockedUsers: [],
  default: [],
  bookmarks: [],
  dateJoined: 1496429065565,
  ageRange: '18-22',
  gender: 'Male' }

I can clearly see all other defaults such as "hasSeenWalkthrough" and "blockedBy/blockedUsers/bookmarks" get set, but my "offersInCategory" and "rejectionsInCategory" for whatever reason don't, though I provide default values for those properties like any others. How do I set these default values using an upsert?



via David Tamrazov

No comments:

Post a Comment