Typegoose v12嵌套对象保存异常:生成_id而非预期结构
Typegoose v12升级后动态键嵌套对象保存异常,仅存_id而非预期结构
问题背景
原代码在Typegoose 5.2.1可正常运行,升级至v12后,本该创建/更新的复杂嵌套对象属性,实际只保存了一个不存在的_id,而非预期的动态键数组结构。
旧版本核心代码:
export class OldSchema extends Typegoose { // ... 其他属性 @prop({ default: {} }) public items: SubObject; } class SubObject { // @ts-ignore @arrayProp({ items: SubNestedObj }) public [key: string]: SubNestedObj[]; } class SubNestedObj { // ... 其他属性 @prop() public word: string; } // 业务逻辑 const x = new OldSchema(); x.items = {}; const y = 'asdfgh'; x.items[y] = []; x.items[y].push({ word: 'somestring' }); console.log('debug1: ', x.items[y]) // [ { word: 'somestring' } ] console.log('debug2: ', x.items) // { _id: new ObjectId('6916df9937950cbd8e818ede') }
预期数据库结构:
{ "_id": ObjectId("xxx"), "items": { "cat": [ { "word": "somestring" } ], "dog": [] } }
已尝试过的无效方案:
- 在嵌套层级使用
type: () => ... - 配置
{ allowMixed: Severity.ALLOW, type: mongoose.Schema.Types.Mixed } - 使用
@modelOptions装饰器 - 无法移除代码中的
@ts-ignore
解决方案
Typegoose v12对嵌套文档的处理逻辑有较大变更,尤其是动态键(索引签名)场景,需明确将SubObject标记为无_id的嵌套对象,同时调整属性装饰器的使用方式:
1. 修改SubObject的装饰器配置
用@prop替代旧版的@arrayProp,显式设置_id: false禁用自动生成_id,同时指定数组类型适配动态键:
import { prop, Typegoose, Severity } from '@typegoose/typegoose'; class SubNestedObj { @prop() public word: string; } class SubObject { // 保留@ts-ignore兼容索引签名 // @ts-ignore @prop({ type: () => [SubNestedObj], _id: false, allowMixed: Severity.ALLOW }) public [key: string]: SubNestedObj[]; } export class OldSchema extends Typegoose { @prop({ default: {}, type: () => SubObject, _id: false // 确保嵌套对象不生成_id }) public items: SubObject; }
2. 调整业务逻辑赋值方式
避免直接将x.items替换为纯对象,基于默认空对象操作,建议用类实例而非字面量赋值:
const x = new OldSchema(); const y = 'asdfgh'; x.items[y] = []; x.items[y].push(new SubNestedObj({ word: 'somestring' }));
3. 关键说明
- Typegoose v12默认会为所有嵌套文档自动生成
_id,必须显式设置_id: false禁用该行为 - 动态键场景下,需用
@prop结合type: () => [SubNestedObj]指定数组类型,替代旧版@arrayProp - 嵌套层级需配置
allowMixed: Severity.ALLOW,允许动态键的混合类型结构
内容的提问来源于stack exchange,提问作者Roman Nozhenko
相关产品推荐
相关产品推荐

