You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB findOneAndUpdate返回null问题及评论投票功能实现求助

评论投票功能问题排查与解决

问题概述

实现评论投票功能时,要求登录用户不能给自己的评论投票,但调用Comment.findOneAndUpdate后返回null;同时不清楚如何通过nModified和ok属性判断评论是否更新成功。

原控制器代码

exports.voteComment = (req, res) => {
  const { commentId } = req.params;
  if (!ObjectId.isValid(commentId)) {
    return res.status(400).send({
      error: "Comment ID not valid",
    });
  }
  console.log(typeof req.auth._id);
  Comment.findOneAndUpdate(
    { commentId, "comment.postedBy": { $ne: req.auth._id } },
    { $push: { votes: req.auth._id } },
    { new: true }
    // { omitUndefined: true }
    // { returnNewDocument: true }
  ).exec((err, result) => {
    if (err) {
      return res.status(400).json({
        error: "Could not vote on that comment",
      });
    }
    console.log(result);
    res.json(result);
    // if (result.nModified) {
    //   console.log("test");
    // }
  });
};

Comment模型代码

const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;

const commentSchema = new mongoose.Schema(
  {
    content: {
      type: String,
      required: true,
      trim: true,
      max: 200,
    },
    postedBy: {
      type: ObjectId,
      ref: "User",
      required: true,
    },
    feature: {
      type: ObjectId,
      ref: "Feature",
      required: true,
    },

    votes: [{ type: ObjectId, ref: "User" }],
    replies: [
      {
        content: {
          type: String,
          required: true,
          trim: true,
          max: 200,
        },
        postedBy: {
          type: ObjectId,
          ref: "User",
        },
        created: {
          type: Date,
          default: Date.now,
        },
        votes: [
          {
            postedBy: {
              type: ObjectId,
              ref: "User",
            },
            created: {
              type: Date,
              default: Date.now,
            },
          },
        ],
      },
    ],

  },
  { timestamps: true }
);

module.exports = mongoose.model("Comment", commentSchema);

问题原因分析

  1. 查找字段错误:
    • Mongoose默认文档ID字段是_id,原代码用自定义的commentId作为查询条件,无法匹配到目标文档。
    • 模型中postedBy是一级字段,原代码错误使用"comment.postedBy"嵌套路径,导致权限判断条件失效。
  2. ID类型不匹配:req.auth._id可能是字符串类型,而模型中postedBy是ObjectId类型,类型不匹配会导致$ne判断逻辑失效。
  3. 缺少重复投票拦截:未判断用户是否已投票,可能导致同一个用户ID被重复添加到votes数组。

修正后的代码与实现

优化后的控制器方法(使用async/await更易维护)

const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const Comment = require("../models/Comment"); // 根据实际文件路径调整

exports.voteComment = async (req, res) => {
  const { commentId } = req.params;
  
  // 验证评论ID合法性
  if (!ObjectId.isValid(commentId)) {
    return res.status(400).json({ error: "评论ID无效" });
  }

  try {
    // 统一用户ID类型为ObjectId
    const userId = typeof req.auth._id === "string" 
      ? mongoose.Types.ObjectId(req.auth._id) 
      : req.auth._id;

    // 开启rawResult获取MongoDB原始响应,包含nModified等元数据
    const updateResult = await Comment.findOneAndUpdate(
      {
        _id: commentId,
        postedBy: { $ne: userId }, // 排除自己发布的评论
        votes: { $ne: userId }     // 防止重复投票
      },
      { $push: { votes: userId } },
      { new: true, rawResult: true }
    );

    // 无符合条件的文档(评论不存在/是自己的评论/已投过票)
    if (!updateResult.value) {
      return res.status(403).json({
        error: "无法投票:评论不存在、是您自己的评论或已投过票"
      });
    }

    // 检查是否成功更新
    if (updateResult.lastErrorObject.nModified === 0) {
      return res.status(400).json({ error: "投票操作未生效" });
    }

    // 返回更新后的评论数据
    res.json(updateResult.value);
  } catch (err) {
    console.error(err);
    res.status(400).json({ error: "投票失败,请稍后重试" });
  }
};

关于nModified和ok的使用说明

  • 启用rawResult: true选项后,findOneAndUpdate会返回包含以下核心字段的对象:
    • value:更新后的文档(对应new: true的配置结果)
    • lastErrorObject:包含nModified(实际更新的文档数量)、ok(操作是否成功,1为成功)等元数据
  • 如果坚持使用回调方式,同样可以通过rawResult: true获取这些字段:
Comment.findOneAndUpdate(
  // 查询条件
  { _id: commentId, postedBy: { $ne: userId }, votes: { $ne: userId } },
  // 更新操作
  { $push: { votes: userId } },
  // 选项
  { new: true, rawResult: true }
).exec((err, result) => {
  if (err) { /* 错误处理逻辑 */ }
  console.log("更新的文档数:", result.lastErrorObject.nModified);
  console.log("操作是否成功:", result.lastErrorObject.ok);
});

内容的提问来源于stack exchange,提问作者Rohan Srivastava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 20:10:27