You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 01:20:00