如何让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
相关产品推荐
相关产品推荐

