Mongoose runValidators: true 在使用 findOneAndUpdate() 时给出错误的验证错误

问题描述 投票:0回答:1

我在express js中有一个函数可以更新我的项目,如下所示:

projectController.ts

export async function updateProjectStatus(req: Request, res: Response) {
  try {
    const projectCode = req.params.projectCode;
    const { status } = req.body;

    const updatedProject = await Project.findOneAndUpdate(
      { projectCode },
      { status },
      { new: true }
    );

    if (!updatedProject) {
      return res.status(404).send('Project not found');
    }

    res.status(200).send(updatedProject);
  } catch (error) {
    let errorMessage = 'Failed to update project status';
    if (error instanceof Error) {
      errorMessage = error.message;
    }

    res.status(500).send({ message: errorMessage });
  }
}

// PATCH: update project details

type ProjectKeys = keyof ProjectType;

const allowedUpdates: ProjectKeys[] = [
  'name',
  'budget',
  'advance',
  'clientName',
  'clientPhone',
  'clientEmail',
  'clientAddress',
  'clientDetails',
  'endDate',
  'demoLink',
  'typeOfWeb',
  'description',
];

export async function updateProjectDetails(req: Request, res: Response) {
  const projectCode = req.params.projectCode;
  const {
    name,
    budget,
    advance,
    clientName,
    clientPhone,
    clientEmail,
    clientAddress,
    clientDetails,
    endDate,
    demoLink,
    typeOfWeb,
    description,
  } = req.body;

  console.log(req.body);
  console.log(projectCode);

  // Extract valid updates from request body
  const updates = Object.keys(req.body);

  const isValidOperation = updates.every((update) => {
    return allowedUpdates.includes(update as ProjectKeys);
  });

  if (!isValidOperation) {
    return res.status(400).send({ error: 'Invalid updates!' });
  }

  try {
    const project = await Project.findOne({ projectCode });
    if (!project) {
      return res.status(404).send({ error: 'Project not found' });
    }

    const updatedProject = await Project.findOneAndUpdate(
      { projectCode },
      {
        name,
        budget,
        advance,
        clientName,
        clientPhone,
        clientEmail,
        clientAddress,
        clientDetails,
        endDate,
        demoLink,
        typeOfWeb,
        description,
      },
      { new: true}
    );

    res.status(200).send(updatedProject);
  } catch (error) {
    res.status(500).send({
      message:
        error instanceof Error
          ? error.message
          : 'Failed to update project details',
    });
    console.log(error);
  }
}

在这里我获取更新的项目详细信息,然后找到该项目,然后更新它。在更新它时,我使用

runValidators: true
在我的项目模型中运行验证器。 我的
projectModel.ts
中有一些验证器,如下所示:

import mongoose from 'mongoose';
import { ProjectType } from '../types/projectDocumentType';

const projectSchema = new mongoose.Schema<ProjectType>(
  {
    projectCode: {
      type: String,
      required: true,
      unique: true,
    },
    name: {
      type: String,
      required: true,
      trim: true,
    },
    budget: {
      type: Number,
      required: true,
      validate: {
        validator: function (value: number) {
          return value >= 0;
        },
        message: 'Budget must be a positive number',
      },
    },
    advance: {
      type: Number,
      required: true,
      validate: {
        validator: function (value: number) {
          return value >= 0 && value <= this.budget;
        },
        message:
          'Advance must be a positive number and less than or equal to the budget',
      },
    },
    due: {
      type: Number,

      validate: {
        validator: function (value: number) {
          return value >= 0 && value <= this.budget;
        },
        message:
          'Due must be a positive number and less than or equal to the budget',
      },
    },
    totalPaid: {
      type: Number,
      default: 0,
      validate: {
        validator: function (value: number) {
          return value >= 0 && value <= this.budget;
        },
        message:
          'Total Paid must be a positive number and less than or equal to the budget',
      },
    },
    clientName: {
      type: String,
      required: true,
      ref: 'Client',
    },
    clientPhone: {
      type: String,
      required: true,
    },
    clientEmail: {
      type: String,
      required: true,
    },
    clientAddress: {
      type: String,
    },
    clientDetails: {
      type: String,
    },
    startDate: {
      type: String,
      required: true,
      default: new Date().toISOString().split('T')[0],
    },

    endDate: {
      type: String,
      required: true,
    },
    demoLink: {
      type: String,
    },
    typeOfWeb: {
      type: String,
    },
    description: {
      type: String,
    },
    status: {
      type: Boolean,
      required: true,
      default: false,
    },

    verifiedClientList: [
      {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Client',
      },
    ],
    projectManager: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
      required: true,
    },
    paymentList: [
      {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Payment',
      },
    ],
  },
  {
    timestamps: true,
  }
);

projectSchema.pre('save', function (next) {
  if (this.isNew) {
    // Only calculate due when creating a new project
    this.due = this.budget - this.advance;
  }
  next();
});

const Project = mongoose.model<ProjectType>('Project', projectSchema);

export default Project;

projectMode.ts
提前和到期部分我有验证器功能。每当我尝试添加新项目时它都工作得很好。但是当我尝试使用邮递员更新项目时,它给了我验证错误,尽管我的 json 是正确的。例如,我发送 json 的补丁请求为:

{
  "name": "Project Alpha",
  "budget": 10000,
  "advance": 900,
  "clientName": "Rezaul",
  "clientPhone": "1234567890",
  "clientEmail": "[email protected]",
  "clientAddress": "123 Main St",
  "clientDetails": "Long-term client",

  "endDate": "2024-06-01",
  "demoLink": "http://example.com/demo",
  "typeOfWeb": "E-commerce",
  "description": "A high-end e-commerce platform"
 
}

但是当我发送它时,它显示我错误:验证失败:预付款:预付款必须是正数并且小于或等于预算但这里提前(900)< budget (10000). so why my validator is not working with

runValidators: true
以及如何在不使用
save()的情况下解决这个问题

使用时我很期待

{
  "name": "Project Alpha",
  "budget": 10000,
  "advance": 900,
  "clientName": "Rezaul",
  "clientPhone": "1234567890",
  "clientEmail": "[email protected]",
  "clientAddress": "123 Main St",
  "clientDetails": "Long-term client",

  "endDate": "2024-06-01",
  "demoLink": "http://example.com/demo",
  "typeOfWeb": "E-commerce",
  "description": "A high-end e-commerce platform"
 
}

它将通过检查验证器来成功更新项目。

node.js mongodb express mongoose mongoose-schema
1个回答
0
投票

我通过使用后架构定义验证或使用path().validate():

进行基于路径的验证来解决问题。例如,对于 advance
 中的 
projectModel.ts
,我使用:

projectSchema.path('advance').validate(function (value: number) { console.log('this.budget', this.get('budget')); return value >= 0 && value <= this.get('budget'); }, 'Advance must be a positive number and less than or equal to the budget');
这里我使用 

this.get('budget')

 获取更新的预算值。这给了我当前的预算值。根据猫鼬官方文档,
validate()
validateSync()
 中运行时,验证者可以使用 
this
 访问文档。当使用更新验证器运行时,
this
是查询,
不是正在更新的文档!查询有一个 get()
 方法,可让您获取更新的值。
Link 因此,在更新我在 mongoose 的 this.get()
 方法中传递的文档之前,我使用 
findOneAndUpdate()
 来获取验证中的更新值。

const updatedProject = await Project.findOneAndUpdate( { projectCode }, { name, budget, advance, clientName, clientPhone, clientEmail, clientAddress, clientDetails, endDate, demoLink, typeOfWeb, description, }, { new: true, runValidators: true } );
此验证现在适用于猫鼬中的 

save()

 方法和 
findOneAndUpdate()
。
如果您使用基于路径的验证,请确保删除基于架构的验证。我的意思是我还删除了 
advance
 部分中的验证和验证器功能。

validate: { validator: function (value: number) { return value >= 0 && value <= this.budget; }, message: 'Advance must be a positive number and less than or equal to the budget', },
并且还可以在 

runValidators: true

 内使用 
findOneAndUpdate()
 作为选项。

© www.soinside.com 2019 - 2024. All rights reserved.