给mongoose find()/findOne()查询的结果添加额外的属性

在学习 mongoose 的时候,碰到一个需要注意的地方。
给查询结果添加额外的属性时,不能直接在这个结果对象上添加属性。原因和解决方案往下看。

假设 User 集合有一个 name 字段:

const User = new mongoose.Schema({ 'name': String }); 

(添加一些数据)加上它附带的 _id 字段,应该如下:

> User.find().pretty();
//结果
[
    {
        "_id": ObjectId("62449223fb0988f6c2cecf3d"),
        "name": 'wffw'
    },
    {
        "_id": ObjectId("62449223fbca2354d3daf8fca"),
        "name": 'luyu'
    },
    ……
]

当我查询结果之后,想要添加一个属性给每一个结果时候,神奇的一幕发生了!

 User.find().then((list) => { 
     list.map((item, index) => {
         console.log('1---', item);         // (1)
         item.str = '给item添加一个 str 属性。';  // (2)
         console.log('2---', item);  // (3)
     })
 }) 
// 结果
1--- [
    {
        "_id": ObjectId("62449223fb0988f6c2cecf3d"),
        "name": 'wffw'
    },
    ……
]
2--- [
    {
        "_id": ObjectId("62449223fb0988f6c2cecf3d"),
        "name": 'wffw'
    },
    ……
]

上面 (3) 输出的结果出乎我意料,和 (1) 的结果一模一样,没有发现 str 属性,我的 str 呢?(遇事不决,量子力学?)

这当然不是量子问题。会不会是 这个 item 是只读的,(2)处根本没有赋值成功? 既然如此,那就不直接操作 item ,创建一个新的对象试试(方式一):

 User.find().then((list) => { 
     list.map((item, index) => {
        let one = {
            _id: item._id,
            name: item.name,
            str: '给item添加一个 str 属性。'
        }
        console.log('4---', item); // (4) 
        console.log('5---', mylist);  // (5)
     })
     
 }) 
// 结果
5--- {
      "_id": ObjectId("62449223fb0988f6c2cecf3d"),
      "name": 'wffw',
      "str": '给item添加一个 str 属性。'
    }

// 果然如此呐,哈哈

那么,,,

到这里你以为就结束了? item 真的是只读的吗?事实就是如此的吗?

(真相~ 真香~)

听说过 getOwnPropertyDescriptors() 吧,打印一下 item的属性描述符:

 User.find().then((list) => { 
     list.map((item, index) => {
          item.str = '这是一个新的属性';
          console.log('6---', item)   // (6) 
          console.log('list[' + index + ']---', Object.getOwnPropertyDescriptors(item));  // (7)
     })
 }) 
// 结果
//毋庸置疑,(6) 打印的结果里没有 str。

(7) 打印的结果 会是什么呢?如下:

// (7) 打印的结果:取其中一个:
list[0]--- {
  '$__': {
    value: InternalCache {
      activePaths: [StateMachine],
      strictMode: true,
      skipId: true,
      selected: {},
      fields: {},
      exclude: null,
      _id: new ObjectId("62449223fb0988f6c2cecf3d")
    },
    writable: true,
    enumerable: true,
    configurable: true
  },
  '$isNew': {
    value: false,
    writable: true,
    enumerable: true,
    configurable: true
  },
  _doc: {
    value: {
      _id: new ObjectId("62449223fb0988f6c2cecf3d"),
      name: 'wffw',
      __v: 0
    },
    writable: true,
    enumerable: true,
    configurable: true
  },
  str: { 
      value: '这是一个新的属性', 
      writable: true, 
      enumerable: true, 
     configurable: true 
  }
}

前两个属性(”$__”、”$isNew”)忽略,仔细看最后两个属性:_doc 里的属性才是 我们cosole.log(item) 的结果!str 并不是没有添加成功,item 并不是只读的!

Emm……#?!$@*……

现在知道了吧,find().then() 或者 findOne().then() 得到的结果,是有一层封装,在获取这个结果的时候,会自动解封,但是 在自己添加属性的时候,不会自动解封。官方说法:

Mongoose models provide several static helper functions for CRUD operations. Each of these functions returns a mongoose `Query` object.

Mongoose模型为CRUD 操作提供了几个静态辅助函数。这些函数中的每一个都返回一个 mongooseQuery对象。

所以,除了(方式一),还有一种方式,赋给 item._doc (方式二) :

 User.find().then((list) => { 
     list.map((item, index) => {
        console.log('8---', item); // (8) 
        item._doc.str = '给item添加一个 str 属性。';
         console.log('9---', item); // (9) 
     })
 }) 
// (8) 略
// (9) 结果:
1--- [
    {
        "_id": ObjectId("62449223fb0988f6c2cecf3d"),
        "name": 'wffw',
        "str": '给item添加一个 str 属性。'
    },
    ……
]

舒服了。

总结: 方式一 和方式二 都可以,推荐方式一,因为这不需要额外知道”_doc”。

有问题反馈加微信:mue233 私聊问我 微信公众号:焦虑自愈教程,分享过去走出来的经验
52软件资源库 » 给mongoose find()/findOne()查询的结果添加额外的属性