Mongoose中向文档数组push元素仅保留首个属性的原因咨询
这个问题的核心是你的Schema定义和实际传入的数据结构不匹配,导致Mongoose在处理时自动过滤了不符合要求的字段。咱们一步步拆解:
先看你的Schema问题
你定义的filters数组里的子文档结构中,items是一个单个对象:
let projectSchema = new Schema({ filters: [ { name: { type: String, required: true}, items: { q: { type: Number, required: true} } // 这里是单个对象,不是数组 } ], });
但你实际push的filter里,items是一个数组:
console.log(filter); // { name: 'abc', items: [ { q: 3}] }
Mongoose的文档对象是严格遵循Schema规则的,当你往filters数组里push一个不符合子Schema结构的对象时,它会自动丢弃那些和Schema定义不匹配的部分——因为你的Schema里items应该是单个包含q的对象,而不是数组,所以Mongoose无法识别这个数组类型的items,直接把整个items字段给过滤掉了,最终就只留下了符合Schema的name字段和自动生成的_id。
解决方法
1. 修正Schema(推荐)
既然你实际要存储的是多个q对象,直接把items改成数组类型,和你传入的数据结构匹配:
let projectSchema = new Schema({ filters: [ { name: { type: String, required: true}, items: [{ q: { type: Number, required: true} }] // 改为数组 } ], });
修正后,你再push{ name: 'abc', items: [ { q: 3}] }这样的对象,Mongoose就能正确识别并保存整个结构,同时还能正常触发验证规则(比如q必须是数字且必填),完全满足你不想用$push的需求。
2. 匹配现有Schema调整传入数据(不推荐,除非你确实只需要单个items对象)
如果你的Schema定义是正确的(即每个filter的items只能是单个对象),那就要调整push的filter结构,让items是单个对象而不是数组:
const filter = { name: 'abc', items: { q: 3} }; // 去掉数组包裹 project.filters.push(filter);
这样push后,items字段就能正常被保存下来。
验证生效的说明
当你用上述正确的方式push后,Mongoose会在save()时自动触发验证:比如如果你的filter里items没有q,或者q不是数字,save()就会抛出验证错误,完全符合你想要利用Mongoose验证特性的需求。
内容的提问来源于stack exchange,提问作者Joe

