【问题标题】:findOne filtering by objectId always returns undefined按 objectId 过滤的 findOne 总是返回 undefined
【发布时间】:2019-12-27 00:36:50
【问题描述】:

开发 node.js 应用程序。由于某种原因,这个 findOne 调用总是返回未定义,即使我已经验证 req.params.id 是有效的并且它应该返回数据......

let event = await Event.findOne({ venue: ObjectId(req.params.id) });

我也试过....

let event = await Event.findOne({ venue: req.params.id });

这是我的事件模型定义的一部分......

const EventSchema = new mongoose.Schema({
  eventDate: {
     type: Date
  },
  venue: {
     type: mongoose.Schema.ObjectId,
     ref: 'Venue'
  },

在邮递员中,我正在对 /venues/5e0401c4a246333ca4ced332 url 执行 DELETE http 动词以供您参考。

基本上我想在事件表中搜索场地 ID。在我决定删除之前,我正在查看该场地是否正在被某个活动使用。

这是整个方法...

// @desc    Delete venue
// @route   DELETE /api/v1/venues/:id
// @access  Private
exports.deleteVenue = asyncHandler(async (req, res, next) => {
  let venue = await Venue.findById(req.params.id);

  if (!venue) {
    return next(
      new ErrorResponse(`No venue with the id of ${req.params.id}`, 404)
    );
  }

  if (req.user.role !== 'manager' && req.user.role !== 'admin') {
    return next(new ErrorResponse(`Not authorized to delete venue`, 401));
  }

  // the following line always returns undefined even though the venue 
  // exists in the events table.... then it jumps to the end of the method
  let event = await Event.findOne({ venue: ObjectId(req.params.id) });

  if (event) {
    return next(
      new ErrorResponse(
        `You cannot delete a venue because events are tied to it.`,
        404
      )
    );
  }

  await Venue.remove();

  res.status(200).json({
    success: true,
    data: {}
  });
});

使用 Compass,查看事件集合我肯定会看到使用我提交的 id 的记录...

_id:5e045b6e0c38f2502440ecb7
attendees:Array
eventDate:2020-01-01T05:00:00.000+00:00
venue:5e0401c4a246333ca4ced332
status:"planning"

我做到了……

  console.log(`id is ${req.params.id}`);
  let event = await Event.findOne({ venue: req.params.id });

结果显示我传递了正确的 id....(控制台输出)

id is 5e0401c4a246333ca4ced332
ReferenceError: Event is not defined
    at C:\Projects\abc\controllers\venues.js:90:15

任何见解将不胜感激。谢谢!

【问题讨论】:

  • 你得到的req.params.id的值是多少。
  • 你确定你有那个venue的记录吗?
  • 能否也请您发布您目前拥有的删除功能的完整代码
  • @AnkitaKuchhadiya 场地 ID 是 5e0401c4a246333ca4ced332
  • await Event.findById 应该是await Event.findOne()

标签: node.js mongodb mongoose


【解决方案1】:

您似乎没有导入您的事件模型。 您需要添加:

const Event = require("../models/event"); //you need to change the path 

之后你需要找到这样的事件: Event.findOne({ venue: req.params.id }).

另外我有几点建议:

1-) 一开始检查角色授权更有意义。

2-) 首先检查给定地点是否有任何事件,如果没有事件,则使用findByIdAndDelete 方法。这样我们可以减少数据库访问次数,因为我们消除了Venue.findById

3-) 如果场地有活动,使用 404 状态码似乎不正确。 我认为 400 - Bad request 更合适。

4-) mongoose 转换_id,所以不需要使用ObjectId。

exports.deleteVenue = asyncHandler(async (req, res, next) => {

  if (req.user.role !== "manager" && req.user.role !== "admin") {
    return next(new ErrorResponse(`Not authorized to delete venue`, 401));
  }

  let event = await Event.findOne({ venue: req.params.id });

  if (event) {
    return next(new ErrorResponse(`You cannot delete a venue because events are tied to it.`,400));
  }

  let venue = await Venue.findByIdAndDelete(req.params.id);

  console.log(venue);
  if (!venue) {
    return next(new ErrorResponse(`No venue with the id of ${req.params.id}`, 404));
  }

  res.status(200).json({
    success: true,
    data: {}
  });
});

测试:

假设我们有以下两个 Venue 文件。

{
    "_id" : ObjectId("5e0471e3394d1e2b348b94aa"),
    "name" : "Venue 1",
},
{
    "_id" : ObjectId("5e0471eb394d1e2b348b94ab"),
    "name" : "Venue 2",
}

还有一个活动文档,其地点是场地 1,ID 为 5e0471e3394d1e2b348b94aa:

{
    "_id" : ObjectId("5e04727c76da213f8c9bf76a"),
    "eventDate" : ISODate("2019-12-26T11:41:16.019+03:00"),
    "name" : "Event 1",
    "venue" : ObjectId("5e0471e3394d1e2b348b94aa")
}

当我们要删除Venue 1时,会出现以下错误,因为它有一个事件:

You cannot delete a venue because events are tied to it.,状态码为 400。

【讨论】:

  • 谢谢。但是如果我尝试这个,事件总是未定义的事件: let event = await Event.findOne({ place: req.params.id });
  • @WebDevGuy2 我测试了这段代码,它可以工作。我猜您没有正确发送 id 参数。请检查。
  • @WebDevGuy2 c你能在开头添加一个console.log(req.params.id)并检查它是否正确以及现有的场地ID吗?
  • 我发布了我在邮递员中使用的删除路径。我正在检查 findOne 行中的请求参数。它是正确的。 :(太奇怪了。
  • @WebDevGuy2 检查它是否是集合中的现有 id。另外你的路由器的签名是什么?它必须在路由 url 中有 :id,例如 router.delete("/venue/:id")
【解决方案2】:

用 mongoose 的 findOneAndDelete 和 Expressjs 来做:

const express = require("express");
const router = express.Router();

router.delete("/:id", (req, res) => {
  if (!mongoose.Types.ObjectId.isValid(req.params.id)) { //checking if id valid
    return res.send("Please provide valid id");
  }
  var id = mongoose.Types.ObjectId(req.params.id);  // passing it into a var
  Event.findOneAndDelete({ venue: id }).then( res.json({ success: true }));
});

module.exports = router;

详情https://mongoosejs.com/docs/api/query.html#query_Query-findOneAndDelete

【讨论】:

  • 我想在事件表中搜索场地 ID。基本上,在我决定删除它之前,我会看看这个场地是否正在被某个活动使用。
【解决方案3】:
exports.deleteVenue = asyncHandler(async (req, res, next) => {

  //First check role. Because it not call database
  if (req.user.role !== 'manager' && req.user.role !== 'admin') {
    return next(new ErrorResponse(`Not authorized to delete venue`, 401));
  }

  //Next step, check event
  const event = await Event.findById({ venue: ObjectId(req.params.id) });

  if (event) {
    return next(
      new ErrorResponse(
        `You cannot delete a venue because events are tied to it.`,
        404
      )
    );
  }

  //Delete venue by Id
   await Venue.deleteOne({ id: req.params.id }, (error, result) =>{
      if(error) return next(
      new ErrorResponse(`No venue with the id of ${req.params.id}`, 404)
    );

      res.status(200).json({
         success: true,
         data: {}
       });
   })

});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 2017-03-18
    • 2016-01-16
    • 1970-01-01
    • 2016-02-10
    相关资源
    最近更新 更多