无法向(猫鼬)对象添加其他元素

Posted

技术标签:

【中文标题】无法向(猫鼬)对象添加其他元素【英文标题】:Can not add additional element to (mongoose) object 【发布时间】:2019-09-04 10:25:15 【问题描述】:

我有一个带有 api 的 nodejs express 应用程序,用于从 mongodb 数据库返回数据。这是我的猫鼬模型:

const bookingSchema = new mongoose.Schema(
  timestamp: 
    type: Date,
    default: Date.now,
    required: true
  ,
  tags: 
    type: [String],
    required: true
  ,
  amount: 
    type: Number,
    required: true
  ,
  type: 
    type: String,
    required: true,
    enum: ['expense', 'income']
  
)

当我使用路径 /api/bookings/listbymonth/2019/1 调用 api 时,后端内的这个函数被调用:

const bookingsListByMonth = (req, res) => 
  const year = ("0000" + req.params.year).slice(-4)
  const month = ("0000" + req.params.month).slice(-2)
  const dateOfMonth = `$year$month01`
  const start = moment(dateOfMonth).startOf("month")
  const end = moment(dateOfMonth).endOf("month")

  bookingMongooseModel
    .find(
      timestamp: 
        $gt: start,
        $lt: end
      
    )
    .sort( timestamp: 1 )
    .exec((err, bookings) => 
      if (!bookings) 
        return res
          .status(404)
          .json(
            "message": "booking not found"
          )
       else if (err) 
        return res
          .status(404)
          .json(err)
      
      res
        .status(200)
        .json(processBookings(bookings));
    )

我不想简单地返回 json 数据,而是想对数据进行预处理并制作一个漂亮的时间戳和货币字段。这就是 json 数据通过一个额外的 processBookings 函数运行的原因。为了测试,我尝试添加另一个字段timestamp2: 123

const processBookings = (bookings) => 
  console.log("Bookings unsorted: \n" + bookings + "\n")

  const mainTags = [
    "Essen",
    "Essen gehen",
    "Notwendiges",
    "Luxus",
  ]

  let bookingsProcessed = []

  mainTags.forEach((tag) => 
    let singleTagBookings = bookings.filter(
      booking => booking.tags.includes(tag)
    )

    singleTagBookings.map((item) => 
      item.timestamp2 = "123"
      return item
    )

    let message = null;
    if (singleTagBookings.length === 0) 
      message = "No bookings found";
    

    bookingsProcessed.push(
      name: tag,
      bookings: singleTagBookings,
      message: message
    )
  );

  console.log("Bookings sorted:")
  bookingsProcessed.forEach((item) => 
    console.log(item)
  )

  return bookingsProcessed

bookings 数组中的对象应该有另一个属性timestamp2: "123",但它们没有。这是输出:

Bookings unsorted: 
 tags: [ 'Luxus', 'voluptatem', 'atque', 'qui', 'sunt' ],
  _id: 5cb2c9e1ff6c9c6bef95f56f,
  timestamp: 2019-01-06T08:53:06.945Z,
  amount: 68.02,
  type: 'expense',
  __v: 0 , tags: [ 'Essen gehen', 'ut', 'unde', 'et', 'officiis' ],
  _id: 5cb2c9e1ff6c9c6bef95f56e,
  timestamp: 2019-01-09T20:35:06.411Z,
  amount: 33.77,
  type: 'income',
  __v: 0 

Bookings sorted:     
 name: 'Essen', bookings: [], message: 'No bookings found' 
 name: 'Essen gehen',
  bookings: 
   [  tags: [Array],
       _id: 5cb2c9e1ff6c9c6bef95f56e,
       timestamp: 2019-01-09T20:35:06.411Z,
       amount: 33.77,
       type: 'income',
       __v: 0  ],
  message: null 
 name: 'Notwendiges',
  bookings: [],
  message: 'No bookings found' 
 name: 'Luxus',
  bookings: 
   [  tags: [Array],
       _id: 5cb2c9e1ff6c9c6bef95f56f,
       timestamp: 2019-01-06T08:53:06.945Z,
       amount: 68.02,
       type: 'expense',
       __v: 0  ],
  message: null 

正如 cmets 建议的那样,我尝试使用 let bookings = [ tags: ["Essen"]]; 作为测试数据。在这里有效。输出是:

Bookings unsorted: 
[object Object]

Bookings sorted:
 name: 'Essen',
  bookings: [  tags: [Array], timestamp2: '123'  ],
  message: null 
 name: 'Essen gehen',
  bookings: [],
  message: 'No bookings found' 
 name: 'Notwendiges',
  bookings: [],
  message: 'No bookings found' 
 name: 'Luxus', bookings: [], message: 'No bookings found' 

所以我想这与我的猫鼬模型限制添加任何其他字段有关。但是,如果我把

console.log("EXTENSIBLE " + Object.isExtensible(bookings))
res
  .status(200)
  .json(processBookings(bookings));

进入我的bookingsListByMonth 函数,我得到:

EXTENSIBLE true

所以理论上我应该可以向bookings 对象添加一些东西?

作为一种解决方法,我将timestamp2 字段添加到我的猫鼬模型中:

const bookingSchema = new mongoose.Schema(
  timestamp: 
    type: Date,
    default: Date.now,
    required: true
  ,
  timestamp2: 
    type: String,
    default: null
  ,
  tags: 
    type: [String],
    required: true
  ,
  amount: 
    type: Number,
    required: true
  ,
  type: 
    type: String,
    required: true,
    enum: ['expense', 'income']
  
)

这可行,但是它在我的数据库中添加了一个额外的无用数据字段。如何修改从 mongodb 返回的bookings json 对象?如果因为是猫鼬模型而无法修改,如何制作可编辑的副本?

【问题讨论】:

不,代码按预期工作...顺便说一下,您的代码也会更改 singleTagBookings 中的对象,因此,您可以改用 .forEach - 是数组singleTagBookingssealed 也许? 如果不是用正确的代码和数据更新问题,你一定会收到错误singleTagBookings.map is not a function 对象未密封。可悲的是我没有收到错误。我已经用完整的代码更新了我的问题。 正如@JaromandaX 报告的那样,代码工作正常 - 尝试复制它并使用let bookings = [ tags: ["Essen"]]; 获取测试数据。请注意,bookings 数组的 input 版本正在更新,不得冻结或密封。 @traktor53 或设为不可扩展 【参考方案1】:

查询返回的文档是限制添加新字段的 mongoose 文档。为了将 mongoose 文档转换为纯 javascript 对象,mongoose 中有一个方法/选项 lean - https://mongoosejs.com/docs/tutorials/lean.html

查找查询看起来像这样

bookingMongooseModel
.find(
  timestamp: 
    $gt: start,
    $lt: end
  
)
.sort( timestamp: 1 )
.lean()

此外,猫鼬提供了可配置的选项供您在定义架构时进行设置。例如, new Schema(.., timestamps: true);将在您的文档中创建两个字段 createdAt 和 updatedAt。有关更多信息,请参阅此处的选项部分 https://mongoosejs.com/docs/guide.html#options

【讨论】:

【参考方案2】:

只需使用 toObject() 函数将您的 mongoose 对象转换为标准 javascript 对象。然后您将能够修改数据/添加新字段/更改数据类型:

 const processBookings = (bookings) => 
     bookings = bookings.map(function(e)return e.toObject(););
     ...

【讨论】:

【参考方案3】:
  singleTagBookings.map((item) => 
      item.timestamp2 = "123"
      return item
    )

我认为这是你的问题..

    map返回一个新数组,所以需要赋值给一个变量 在地图回调函数中,返回一个新对象比改变它更好

所以试试这个

singleTagBookings = singleTagBookings.map((item) => (
       ...item,
       timestamp2: "123"
    ))

【讨论】:

以上是关于无法向(猫鼬)对象添加其他元素的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 jQuery 向元素添加属性

使用猫鼬将对象数组添加到子文档

NodeJS将元素添加到对象

如何从猫鼬模型制作graphql?

猫鼬使用方法将模式添加到模式中

如何使用猫鼬为数组元素添加值?