Mongoose无法删除文档数组元素 ObjectId比对返回false问题
问题根因
你遇到的相等判断返回false、$pull无法删除数组元素的问题,核心是两个原因:
- 首先,Mongoose的
ObjectId是引用类型,直接用==/===比较两个独立的ObjectId实例时,本质是比较对象的内存引用地址,哪怕两个实例存储的id值完全相同,只要不是同一个实例,比较结果都会是false。你打印时值完全一致、typeof都是object,恰好符合这个特征。 - 其次,你的Schema定义存在缺陷,直接使用无类型约束的
Array类型定义数组字段时,Mongoose不会自动做类型校验和转换,数组里很容易混杂字符串格式的id和ObjectId格式的id,类型不匹配时$pull自然无法命中要删除的元素。
修复步骤
- 首先修正Schema定义,给数组字段明确指定元素类型,禁止使用裸
Array定义存储id的数组字段:
const exampleSchema = new mongoose.Schema({ id : String, // 明确指定数组元素为ObjectId类型,如果有关联模型可以加上ref做关联 list: [{ type: mongoose.Schema.Types.ObjectId, ref: '对应关联模型名' }], // 你代码中实际操作的pending字段也要做同样的类型定义 pending: [{ type: mongoose.Schema.Types.ObjectId, ref: '对应关联模型名' }] }) const Example= mongoose.model("Example", exampleSchema );
类型定义完成后,Mongoose会自动对写入数组的id做类型转换,从根源避免同一数组内id类型混乱的问题。
- 替换错误的相等判断逻辑:
ObjectId实例自带equals()方法专门用于值比较,不要直接用==/===判断:
// 正确的比较方式,会返回正确的匹配结果 console.log(req.body.friendId.equals(user.pending[0]))
- 修正更新逻辑:
只要Schema配置了正确的数组类型,$pull操作不需要手动把请求参数转成ObjectId,直接传字符串格式的id即可,Mongoose会自动完成类型匹配:
router.patch("url", async (req, res) => { try { await Example.updateOne( { _id: req.body.friendId }, { $pull: { pending: req.body.userId } }, { new: true } ); res.status(200).send({ msg: "更新成功" }) } catch (err) { res.status(500).send({ error: err.message }) } })
如果你暂时不想调整Schema,需要先排查现有数组中存储的id实际类型:如果数组里存的是字符串格式的id,你手动转成ObjectId去做$pull匹配会全部失效,需要保证匹配值和数组内存储的值类型完全一致才能正常删除。
内容的提问来源于stack exchange,提问作者Bennyh961
相关产品推荐
相关产品推荐

