7
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);

  });
m_rd_n
  • 175
  • 2
  • 11

4 Answers4

12

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;
  },
});
Akshendra Pratap
  • 2,002
  • 1
  • 12
  • 25
  • Thanks @AkshendraPratap. But why when I do `Object.assign()` it shows up, when I do `console.log()` it doesn't. For example, in the 3rd code above `console.log("message")` showed regular doc. but when I did `Object.assign()`, actual data pop out? )) – m_rd_n Jan 03 '18 at 20:59
  • 1
    On a very higher level, to print the object as string, `console.log` will use a `toString()` function. Mongoose provides a `toString` for its documents as helper. Which is basically retuning `toObject`. You can look at the code here, https://github.com/Automattic/mongoose/blob/2e70892bcd4932c7ab0420085e1b9f35da98a263/lib/document.js – Akshendra Pratap Jan 03 '18 at 21:15
4

You can also use .lean() method with mongoose request. This allows to get less cumbersome response and process it easyly:

try {
    const assets = await myModel.Assets
      .find({ isActive: true }, { __v: 0, _id: 0 })
      .lean()
      .exec()
    // do something
}
catch(error) {
  throw error
}
Roman
  • 19,236
  • 15
  • 93
  • 97
1

It appears that the _doc property of mongoose objects should be referenced if you want to either assign to or from those objects. In fact, I was unable to set additional properties in a normal manner like so mongoDoc.newProp = propValue;. It was not altering the original object.

For assignment, instead of:

Object.assign(mongoDoc, {a: 1, b: 2});

You'd want:

Object.assign(mongoDoc._doc, {a: 1, b: 2});

Or if you're assigning the mongoDoc properties to another object, you'd want

Object.assign({a: 1, b: 2}, mongoDoc._doc);

SuperCodeBrah
  • 2,874
  • 2
  • 19
  • 33
0

// add .lean() in your query like below

const documents = await DocumentModel.find().lean();

// at debug now ,
// now you will get your result;
Shashwat Gupta
  • 5,071
  • 41
  • 33