简体   繁体   中英

findOne filtering by objectId always returns undefined

Developing node.js app. For some reason this findOne call always returned undefined, even though I have verified that the req.params.id is valid and it should return data...

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

I've also tried....

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

Here's part of my model definition for Event....

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

In postman I am doing a DELETE http verb against /venues/5e0401c4a246333ca4ced332 url for your information.

Basically I'm wanting to search for the venue id in the events table. I'm seeing if this venue is being used by an event before I decide to delete it.

Here's the entire method...

// @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: {}
  });
});

Using Compass, looking at the events collection I definitely see records using the id I submitted...

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

I did...

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

The results showed I was passing the correct id.... (console output)

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

Any insight would be appreciated. Thanks!

It seems you are not importing your Event model. You need to add:

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

After that you need to find the event like this: Event.findOne({ venue: req.params.id }) .

Also I have a few suggestions:

1-) It makes more sense to check role authorization in the beginning.

2-) First check if there is any Event for the given Venue, and if there is no events, use findByIdAndDelete method. This way we can reduce number of db access, since we eliminated Venue.findById

3-) In the case a venue has events, using a 404 status code does not seem correct. I think 400 - Bad request is more appropriate.

4-) mongoose converts _id's, so there is no need to use 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: {}
  });
});

Test:

Let's say we have the following two Venue document.

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

And one Event document whose venue is Venue 1 with id 5e0471e3394d1e2b348b94aa:

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

When we want to delete the Venue 1, this will result with the following error, because it has an event:

You cannot delete a venue because events are tied to it. with status code 400.

Do it with findOneAndDelete of mongoose and 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;

for details https://mongoosejs.com/docs/api/query.html#query_Query-findOneAndDelete

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: {}
       });
   })

});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM