子文档上的猫鼬findOneAndUpdate对ObjectId字段抛出验证错误

时间:2020-10-01 10:52:23

标签: javascript mongoose mongoose-schema

我有一个基本的ChatRoom和ChatMessage模式。为了进行某种优化,ChatRoom包含lastMessage属性作为ChatMessage类型的子文档。

export const ChatMessageSchema = new Schema({
  message: {
    type: String,
    required: true,
  },
  chatRoomId: {
    type: Schema.Types.ObjectId,
    required: true,
  },
  createdBy: {
    type: Schema.Types.ObjectId,
    required: true,
  },
  ...
}, {
  timestamps: true,
});

export const ChatRoomSchema = new Schema({
  membersIds: {
    type: [Schema.Types.ObjectId],
    required: true,
  },
  lastMessage: {
    type: ChatMessageSchema,
  },
  ...
}, {
  timestamps: true,
});

因此,每当创建新消息时,我都会尝试用lastMessage更新/替换findOneAndUpdate道具。

const onChatMessagePosted = async ({ chatMessage, chatRoom }) => {
  // 1. Doesn't work, throw an "Path `chatRoomId` is required" error
  await ChatRoom.findOneAndUpdate(
    { _id: chatRoom._id },
    { $set: { lastMessage: chatMessage } },
    { new: true, runValidators: true },
  );

  // 2. It works
  chatRoom.set({ lastMessage: chatMessage });
  await chatRoom.save();

  // 3. It works too
  await ChatRoom.findOneAndUpdate(
    { _id: chatRoom._id },
    {
      $set: {
        'lastMessage._id': chatMessage._id,
        'lastMessage.chatRoomId': chatMessage.chatRoomId,
        'lastMessage.createdBy': chatMessage.createdBy,
        ...
      },
    },
    { new: true, runValidators: true },
  );
};

但是由于某些原因,findOneAndUpdate对子文档字段抛出了path *propName* is required错误。

"errors": {
  "lastMessage.chatRoomId": {
    "message": "Path `chatRoomId` is required.",
      "name": "ValidatorError",
      "properties": {
      "message": "Path `chatRoomId` is required.",
        "type": "required",
        "path": "chatRoomId",
        "value": "5f72f8666144a40bb15f368a"
    },
    "kind": "required",
      "path": "lastMessage.chatRoomId",
      "value": "5f72f8666144a40bb15f368a"
  },
  "lastMessage.createdBy": {
    "message": "Path `createdBy` is required.",
      "name": "ValidatorError",
      "properties": {
      "message": "Path `createdBy` is required.",
        "type": "required",
        "path": "createdBy",
        "value": "5ec65435dd1b860d9898609b"
    },
    "kind": "required",
      "path": "lastMessage.createdBy",
      "value": "5ec65435dd1b860d9898609b"
  }
},
"message": "Validation failed: lastMessage.chatRoomId: Path `chatRoomId` is required., lastMessage.createdBy: Path `createdBy` is required.",

令人困惑的部分是:

  • 它仅对type: Schema.Types.ObjectId(在此示例中,lastMessage.message道具通过验证)的字段抛出;
  • 不会为猫鼬save方法抛出;
  • 使用子路径字段不会抛出异常;

这是预期的猫鼬行为吗?如果有什么方法可以使它工作而无需更新每个子文档字段或没有保存方法呢?

谢谢!

1 个答案:

答案 0 :(得分:0)

我想您的问题来自Refs。您应该在ChatRoomSchema下添加ChatMessageSchema的引用。试试这个:

chatMessage.js

const mongoose = require('mongoose');
const ChatMessageSchema = new Schema({
  message: {
    type: String,
    required: true,
  },
  chatRoomId: {
    type: mongoose.Schema.Types.ObjectId,
    required: true,
  },
  createdBy: {
    type: mongoose.Schema.Types.ObjectId,
    required: true,
  },
  ...
}, {
  timestamps: true,
});

module.exports = mongoose.model('ChatMessage', ChatMessageSchema);

chatRoom.js

const mongoose = require('mongoose');
const ChatRoomSchema = new Schema({
  membersIds:[
      { type: mongoose.Schema.Types.ObjectId, ref: 'Member' }
    ],
  lastMessage: {
    type: mongoose.Schema.Types.ObjectId, ref: 'ChatMessage'
  },
  ...
}, {
  timestamps: true,
});
module.exports = mongoose.model('ChatRoom', ChatRoomSchema);