Search code examples
node.jsmongooseassign

Object.assign() creates wierd properties when assigns mongoose doc


MessageThread.findById(req.body._id)
      .populate({ path: "messages" })
      .exec((err, foundMessageThread) => {
        var filtered = foundMessageThread.messages.map(message=>{
          return Object.assign({}, message, {isRead: true});
        })
        console.log("filtered", filtered);

      });

console.log shows:

{ '$__':
 InternalCache {
   strictMode: true,
   selected: {},
   shardval: undefined,
   saveError: undefined,
   validationError: undefined,
   adhocPaths: undefined,
   removing: undefined,
   inserting: undefined,
   version: undefined,
   getters: {},
   _id: 5a4c7f2d8b49fc260c396f55,
   populate: undefined,
   populated: undefined,
   wasPopulated: true,
   scope: undefined,
   activePaths: [Object],
   pathsToScopes: {},
   ownerDocument: undefined,
   fullPath: undefined,
   emitter: [Object],
   '$options': true },
isNew: false,
errors: undefined,
_doc:
 { sentAt: 2018-01-03T06:58:53.188Z,
   isRead: false,
   _id: 5a4c7f2d8b49fc260c396f55,
   sender: 5a4b77767251b44cd870219f,
   reciever: 5a4b780a7251b44cd87021a1,
   text: 'qwe',
   __v: 0 },
'$init': true,
isRead: true },
......

it repeats many times. I suppose it (InternalCache { strictMode: true...) relates to message that is taken from foundMessageThread. And it reveals its metadata(in my term) while assigning. Because:

MessageThread.findById(req.body._id)
  .populate({ path: "messages" })
  .exec((err, foundMessageThread) => {
    var filtered = foundMessageThread.messages.map(message=>{
      console.log("message", message)
      return Object.assign({}, message, {isRead: true});
    })
    console.log("filtered", filtered);

  });

console.log shows

{ sentAt: 2018-01-03T06:58:53.188Z,
  isRead: false,
  _id: 5a4c7f2d8b49fc260c396f55,
  sender: 5a4b77767251b44cd870219f,
  reciever: 5a4b780a7251b44cd87021a1,
  text: 'qwe',
  __v: 0 },
....

My question:

  1. Is it normal behavior?
  2. If it is how to fix it? Because "metadata" prevents objects being assigned.

P.S. I've tried:

MessageThread.findById(req.body._id)
  .populate({ path: "messages" })
  .exec((err, foundMessageThread) => {
    var filtered = foundMessageThread.messages.map(message=>{
      return **Object.assign({}, message._doc, {isRead: true})**;
    })
    console.log("filtered", filtered);

  });

Solution

  • This is a normal behaviour with mongoose. Objects returned by mongoose wrap the actual data, so as to add behaviours (methods) to it.

    You can get to the actual data object by using toObject method, for eg, message.toObject().

    However there are properties like __v, which are used by mongoose for house keeping purposes. If you don't want them, you can modify the toObject method like this

    messageSchema.set('toObject', {
      versionKey: false,
      transform: (doc, ret) => {
        delete ret.__v;
        return ret;
      },
    });