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

如何让Typegoose/Mongoose自动为子文档生成ObjectId?

问题

我正在使用TypeScript、Node.js和MongoDB构建Web应用,采用Typegoose与MongoDB交互。目前需要手动为子文档模型SubPage生成ObjectId,希望能让Typegoose/Mongoose自动完成这个操作。现有模型定义和创建逻辑如下:

模型代码

import { Types } from 'mongoose';
import { getModelForClass, prop } from '@typegoose/typegoose';

class PageContract {
  @prop({ required: true, type: String })
  public title!: string;

  @prop({ required: false, type: String })
  public description?: string;

  @prop({ required: false, type: String })
  public externalLink?: string;

  @prop({ required: true, type: Date, default: Date.now() })
  public createdAt!: Date;
}

export class SubPage extends PageContract {
  @prop({ required: true, type: Types.ObjectId })
  public _id!: Types.ObjectId;
}

export class Page extends PageContract {
  @prop({ required: false, type: Array })
  public subPages?: SubPage[];

  @prop({ required: false, type: Date })
  public publishedAt!: Date;

  @prop({ required: false, type: Date })
  public draftedAt!: Date;

  @prop({ required: false, type: Date })
  public unpublishedAt!: Date;
}

export const PageModel = getModelForClass(Page);
export const SubPageModel = getModelForClass(SubPage);

创建Page的逻辑

export const createPage = ({
  title,
  description,
  externalLink,
  subPages,
  status
}: SavePagePayload): Promise<DocumentType<Page>> => {
  const docSubPages: SubPage[] = [];
  if (subPages && subPages.length > 0) {
    subPages.every(({ title, description, externalLink }) => {
      const subPage = new SubPage();
      subPage._id = new Types.ObjectId(); // 手动生成ObjectId
      subPage.title = title;
      subPage.description = description;
      subPage.externalLink = externalLink;
      docSubPages.push(subPage);
    });
  }

  const statusFields = getNextStatusTimestamps(status);

  return PageModel.create({
    ...statusFields,
    title,
    description,
    externalLink,
    subPages: docSubPages
  });
};
解决方案

只需要三步修改,就能让Typegoose自动为子文档生成ObjectId:

1. 调整子文档SubPage的_id属性配置

在SubPage类的_id字段的@prop装饰器中添加auto: true选项,告诉Typegoose自动生成ObjectId:

export class SubPage extends PageContract {
  @prop({ required: true, type: Types.ObjectId, auto: true })
  public _id!: Types.ObjectId;
}

2. 修正父文档Page中subPages的类型定义

将subPages的@prop配置改为直接指向SubPage类型,而不是泛用的Array,这样Typegoose能正确识别子文档类型并处理自动生成逻辑:

export class Page extends PageContract {
  @prop({ required: false, type: () => SubPage })
  public subPages?: SubPage[];

  // 其他属性保持不变...
}

3. 简化createPage函数

不再需要手动实例化SubPage和赋值_id,直接传入子文档的属性对象即可,Mongoose会自动为每个子文档生成ObjectId:

export const createPage = ({
  title,
  description,
  externalLink,
  subPages,
  status
}: SavePagePayload): Promise<DocumentType<Page>> => {
  const statusFields = getNextStatusTimestamps(status);

  return PageModel.create({
    ...statusFields,
    title,
    description,
    externalLink,
    subPages: subPages?.map(sp => ({
      title: sp.title,
      description: sp.description,
      externalLink: sp.externalLink
    }))
  });
};

原理说明

当子文档的_id字段设置了auto: true,并且父文档中正确指定了子文档的类型时,Mongoose在创建父文档的过程中,会自动为每个子文档实例生成唯一的ObjectId,完全不需要手动干预。

内容的提问来源于stack exchange,提问作者Wai Yan Hein

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:47:03