Node.js+Mongoose删除MongoDB数据:一键有效一键无效求排查
Hey Sam, let's break down what's going on here—your issue boils down to how Express matches route patterns, and a subtle conflict between your two delete routes.
The Root Problem
Express uses pattern matching to route requests, and your two delete routes have identical structural patterns once you account for dynamic parameters:
- First route:
/myprojects/:id/cost/:labour_id/remove - Second route:
/myprojects/:id/cost/:tool_id/remove
To Express, :labour_id and :tool_id are just generic placeholders for dynamic values—they don't make the routes unique. So when you click the second button (triggering a URL like /myprojects/123/cost/456/remove), Express immediately matches it to the first route and never reaches the second one.
Fix 1: Add a Unique Segment to the Route Path
The cleanest solution is to modify the second route to include a distinct segment so Express can tell them apart. Here's how to update your code:
Updated EJS Button for Tools
<td class="td21"> <a href="/myprojects/<%= project._id %>/cost/tool/<%= tool._id %>/remove"> <button type="button" class="btn btn-danger">Remove</button> </a> </td>
Updated Tool Delete Route
app.get("/myprojects/:id/cost/tool/:tool_id/remove", function(req, res){ Tool.findByIdAndRemove(req.params.tool_id, function(err){ if(err){ console.log(err); }else{ Project.findById(req.params.id, function(err, foundProject){ if(err){ console.log(err); }else{ res.redirect("/myprojects/" + req.params.id + "/cost"); } }); } }); });
Fix 2: Use Query Parameters to Distinguish Item Type
If you prefer to keep a single route structure, you can add a query parameter to specify whether you're deleting a labour or tool entry:
Updated EJS Button for Tools
<td class="td21"> <a href="/myprojects/<%= project._id %>/cost/<%= tool._id %>/remove?type=tool"> <button type="button" class="btn btn-danger">Remove</button> </a> </td>
Combined Delete Route
app.get("/myprojects/:id/cost/:item_id/remove", function(req, res){ const itemId = req.params.item_id; const itemType = req.query.type; // Select the correct model based on query param let ModelToDelete; if(itemType === "labour"){ ModelToDelete = Labour; } else if(itemType === "tool"){ ModelToDelete = Tool; } else { return res.status(400).send("Invalid item type"); } ModelToDelete.findByIdAndRemove(itemId, function(err){ if(err){ console.log(err); }else{ res.redirect("/myprojects/" + req.params.id + "/cost"); } }); });
Quick Best Practice Note
While your current setup works, using GET requests for destructive actions like deletion isn't ideal (GET requests can be cached, bookmarked, or accidentally triggered). For production apps, consider using DELETE HTTP methods with forms or AJAX instead—but fixing the route conflict will get your second button working immediately.
内容的提问来源于stack exchange,提问作者Sam

