MongoDB PUT请求无法更新read字段修改EJS元素类名问题
问题背景
- 开发项目为The Odin Project的Library Project,采用MongoDB作为数据存储方案
- 数据库
books集合中read字段存储值为字符串类型的"true"/"false",非布尔值 - 实现目标:为
.change类按钮绑定点击事件,触发PUT请求切换对应书籍的read字段值;更新完成后同步修改EJS渲染元素的类名,根据read值动态改变书籍条目显示颜色 - 已尝试方案:调整常量定义、修改请求体
read字段传值,均未生效,初步判断问题出在app.put接口逻辑
现有代码
前端JS代码
const readButton = document.querySelectorAll(".change"); Array.from(readButton).forEach((element) => { element.addEventListener("click", changeRead); }); async function changeRead() { try { const response = await fetch("changeRead", { method: "put", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ read: "false", }), }); const data = await response.json(); console.log(data); // location.reload(); } catch (error) { console.log(error); } }
Node.js接口代码
注:曾尝试将查询条件的
title: request.body.title修改为read:request.body.read,问题依旧存在
app.put("/changeRead", (request, response) => { db.collection("books") .updateOne( { title: request.body.title }, { $set: { read: "false", }, } ) .then((result) => { console.log("read changed"); response.json("book status changed"); }) .catch((error) => console.log(error)); });
index.ejs模板代码
<% for(let i=0; i<books.length; i++) {%> <div class="col-sm-6 col-md-4 col-lg-3 text-center"> <div class="card book"> <div class="row"> <div class="col-1 binding p-0 <%= books[i].read %>" id="<%= books[i].read %>"></div> <div class="col-10 p-0"> <div class="card-body p-4"> <h5 class="cart-title p-2"> <%= books[i].title %> </h5> <p class="card-text"><%= books[i].author %> </p> <p class="card-text">Pages: <%= books[i].pages %> </p> <p class="card-text">Published: <%= books[i].published %> </p> <button type="button" class="btn text-center change m-1">Change Read </button> <button type='button' class="btn text-center delete my-1">Delete Book </button> </div> </div> </div> </div> </div> <%}%>
MongoDB文档示例
{ "_id" : "redacted", "title" : "The Return of the Kings", "author" : "J.R.R. Tolkien", "pages" : "416", "published" : "", "read" : "true" }
问题根因
- 前端请求未携带目标书籍的唯一标识:当前请求体仅硬编码传入
read: "false",没有传递对应书籍的ID/标题,后端查询条件request.body.title实际为undefined,无法匹配到待更新的文档;且固定传false无法实现true/false双向切换。 - 后端更新逻辑硬编码目标值:接口内固定将
read字段设为"false",未根据书籍原有状态做切换判断;同时使用title作为查询条件容易因同名书籍匹配错误,优先使用MongoDB生成的_id作为唯一查询条件。 - 前端无DOM更新逻辑:当前注释掉了页面刷新代码,接口请求成功后页面不会同步更新样式,无法看到类名变化带来的颜色修改效果。
修复方案
1. 修改EJS模板,给按钮绑定书籍标识
在.change按钮上添加自定义属性,存储当前书籍的_id和已读状态,方便前端点击时获取对应数据:
<button type="button" class="btn text-center change m-1" data-book-id="<%= books[i]._id.toString() %>" data-current-read="<%= books[i].read %>">Change Read </button>
_id调用toString()是为了把MongoDB的ObjectId类型转成字符串,避免前端序列化报错。
2. 修改前端JS逻辑
点击按钮时获取对应书籍的ID和当前状态,计算切换后的目标值,传给后端;请求成功后直接更新DOM类名,无需整页刷新:
const readButton = document.querySelectorAll(".change"); Array.from(readButton).forEach((element) => { element.addEventListener("click", changeRead); }); async function changeRead(e) { const currentBtn = e.currentTarget; const bookId = currentBtn.dataset.bookId; const currentReadStatus = currentBtn.dataset.currentRead; // 计算切换后的状态:当前是true就切为false,反之切为true const newReadStatus = currentReadStatus === "true" ? "false" : "true"; try { const response = await fetch("/changeRead", { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ bookId: bookId, newRead: newReadStatus }), }); const result = await response.json(); if (result.success) { // 更新按钮上存储的状态值,方便下次点击计算 currentBtn.dataset.currentRead = newReadStatus; // 找到当前书籍卡片侧边的binding元素,替换类名和id const bindingBar = currentBtn.closest(".book").querySelector(".binding"); bindingBar.classList.remove(currentReadStatus); bindingBar.classList.add(newReadStatus); bindingBar.id = newReadStatus; } } catch (error) { console.log(error); } }
3. 修改后端PUT接口
引入ObjectId做类型转换,通过书籍_id查询更新对应文档,返回操作结果:
// 文件顶部引入ObjectId,适配MongoDB官方驱动 const { ObjectId } = require("mongodb"); app.put("/changeRead", async (request, response) => { try { const { bookId, newRead } = request.body; const updateResult = await db.collection("books").updateOne( { _id: new ObjectId(bookId) }, { $set: { read: newRead } } ); if (updateResult.modifiedCount === 1) { response.json({ success: true, msg: "书籍阅读状态更新成功" }); } else { response.json({ success: false, msg: "未找到对应书籍或状态无变化" }); } } catch (error) { console.log(error); response.status(500).json({ success: false, msg: "服务端错误" }); } });
内容的提问来源于stack exchange,提问作者jake
相关产品推荐
相关产品推荐

