Express+Mongoose查询MongoDB返回undefined及遍历报错排查
问题根因
三个错误叠加导致了你遇到的所有现象:
- Mongoose的
Model.find()是异步方法,返回Promise/Query对象,原控制器代码没有加await等待查询执行完成,直接把未完成的查询对象传给了EJS模板。最开始模板尝试遍历这个非数组对象时直接触发「无法遍历undefined」的报错;后续调整后遍历到的是Query对象本身的内置属性,这类属性总共有约50个,且都没有name字段,所以渲染出了约50个undefined值。 - EJS模板里遍历数组的语法写错了:
for...in语法用于遍历对象的可枚举键名,遍历数组时拿到的是数组索引(字符串类型的"0"、"1"…)而非数组元素,哪怕查询正常返回了数组,直接访问field.name也会得到undefined。 - 数据库连接串没有指定目标数据库名,Mongoose默认会连接到Atlas集群的
test库,如果你的9条fields数据存在其他业务库下,会出现「客户端工具能查到数据、业务代码查不到」的不一致问题。
修复方案
按顺序修改对应代码即可:
- 首先修改控制器代码,给查询加
await,确保拿到实际的文档数组再传给模板:
const Field = require('../models/field'); module.exports.index = async (req, res) => { // 等待查询完成,拿到真实的文档数组 const fields = await Field.find({}); res.render('fieldInstances/index', {fields}); };
- 然后修改EJS模板,把遍历语法改成适合数组遍历的
for...of,同时修复复选框id重复的问题(多个DOM元素共用同一个id会导致label关联失效):
<div class="modal-body d-flex"> <form action="/formInstance/new" method="GET"> <% // 用for...of遍历数组,直接拿到每个field文档实例 %> <% for (let field of fields) { %> <% // 用文档_id拼接唯一id,避免多元素id重复 %> <input type="checkbox" class="btn-check" id="btn-check-<%= field._id %>" autocomplete="on"> <label class="btn btn-outline-secondary" for="btn-check-<%= field._id %>" name="fieldInstance[field]"><%= field.name %></label><br> <% } %> <button type="submit" class="btn btn-success">To the Form!</button> </form> </div>
- 最后修复数据库连接串,在连接串的/后、?前加上你存储业务数据的实际数据库名,示例如下(把
你的业务库名替换成你自己的库名即可):
async function mongooseConnect() { await mongoose.connect("mongodb+srv://amillerlite:password@projects.brxq6oa.mongodb.net/你的业务库名?retryWrites=true&w=majority"); };
改完重启服务即可正常渲染出9条字段记录。
内容的提问来源于stack exchange,提问作者amiller_lite
相关产品推荐
相关产品推荐

