Mongoose Mixed类型数组findOneAndUpdate报错:无法读取cardsArray属性
问题背景
我编写了编辑卡片的控制器,用于更新cardsArray对象的字段。由于每个卡片对象的字段不同,cardsArray采用mongoose.Schema.Types.Mixed类型存储。新增卡片的addCard控制器运行正常,但调用editCard控制器时出现类型错误:
TypeError: Cannot read properties of null (reading 'cardsArray')
相关代码及数据
Schema定义
const userSchema = new mongoose.Schema( { name: { type: String, required: true, }, email: { type: String, required: true, }, password: { type: String, required: true, }, cardsArray: [{ type: mongoose.Schema.Types.Mixed }], } );
MongoDB存储数据
{ "_id": { "$oid": "63b43ab32fc8d3c100cafecc" }, "name": "usern_name", "email": "pr****@gmail.com", "password": "$2b$12$3nwifHakrBu94BwLXAC4Nu16Kw0.xyW8vAIPTMSgY7cYttVklDIZq", "cardsArray": [ { "title": "some_title", "category": "Bank", "cardHolder": "some_name", "cardNumber": "54545454", "expiry": "23/01", "cvv": "***", "logoIndex": 72, "isFavourite": false, "_id": { "$oid": "63b83cc77288d277ef359533" } } ], "loginIdsArray": [], "docsArray": [], "activitiesArray": [], "__v": 0 }
Add Card控制器代码
addCard: async (req, res) => { console.log(req.body.data, req.body.user_id) req.body.data._id = newObjectId; try { const response = await UserDatabase.findOneAndUpdate( { _id: req.body.user_id }, { $push: { cardsArray: { $each: [req.body.data] }, }, }, { returnOriginal: false } ); res.status(200).send(response); } catch (error) { console.log(error) res.status(404).json({ message: error.message }); } },
Edit Card控制器代码
editCard: async (req, res) => { const id = req.params.id; const { category, title, cardHolder, cardNumber, expiry, cvv, logoIndex, isFavourite } = req.body; console.log(req.params.id) try { const response = await UserDatabase.findOneAndUpdate( { _id: "63b43ab32fc8d3c100cafecc", 'cardsArray._id': "63b709fc69a1cfa6fccd645c" }, { $set: { "cardsArray.$.title": req.body.title, "cardsArray.$.category": req.body.category, "cardsArray.$.cardHolder": req.body.cardHolder, "cardsArray.$.cardNumber": req.body.cardNumber, "cardsArray.$.expiry": req.body.expiry, "cardsArray.$.cvv": req.body.cvv, "cardsArray.$.logoIndex": req.body.logoIndex, "cardsArray.$.isFavourite": req.body.isFavourite } }, ); console.log(response) res.status(201).json(response.cardsArray); } catch (error) { console.log(error) res.status(404).json({ message: error.message }); } }
错误原因分析
- 查询条件不匹配:
editCard控制器里硬编码的卡片ID63b709fc69a1cfa6fccd645c与MongoDB数据中实际的卡片ID63b83cc77288d277ef359533不一致,导致findOneAndUpdate找不到匹配文档,返回null。 - 未指定返回更新后文档:
findOneAndUpdate默认返回更新前的文档,即使找到匹配项,未设置{ new: true }也可能出现数据不一致问题。 - 无null值判断:直接访问
response.cardsArray,当response为null时触发类型错误。
解决方案
- 改用动态参数传递ID:从请求中获取用户ID和卡片ID,避免硬编码,比如从
req.body.user_id和req.params.id取值。 - 设置返回更新后文档:添加
{ new: true }选项,与addCard控制器保持一致。 - 增加null值判断:访问
response属性前先检查是否为null,提前返回错误信息。
修改后的editCard控制器代码:
editCard: async (req, res) => { const cardId = req.params.id; const userId = req.body.user_id; // 根据实际请求方式调整获取用户ID的位置 try { const response = await UserDatabase.findOneAndUpdate( { _id: userId, 'cardsArray._id': cardId }, { $set: { "cardsArray.$.title": req.body.title, "cardsArray.$.category": req.body.category, "cardsArray.$.cardHolder": req.body.cardHolder, "cardsArray.$.cardNumber": req.body.cardNumber, "cardsArray.$.expiry": req.body.expiry, "cardsArray.$.cvv": req.body.cvv, "cardsArray.$.logoIndex": req.body.logoIndex, "cardsArray.$.isFavourite": req.body.isFavourite } }, { new: true } // 返回更新后的文档 ); if (!response) { return res.status(404).json({ message: "用户或卡片不存在" }); } res.status(200).json(response.cardsArray); } catch (error) { console.log(error) res.status(500).json({ message: error.message }); } }
内容的提问来源于stack exchange,提问作者Praveen Lohar
相关产品推荐
相关产品推荐

