使用TypeORM/NestJS查询MongoDB无法获取关联user及statements如何解决
问题描述
我在MongoDB中有一条数据库条目,存储了context名称(文本)、添加该条目的用户以及内部的statements数据。但我查询时仅能获取到context名称和创建时间,无法获取用户id和statements内容,想请教我的操作存在什么问题,该如何修复?
我的MongoDB条目示例如下:
{ "_id":{"$oid":"615314c9ba504ed1f92af7a7"}, "context":{"contextName":"luchkas1", "statements":[], "user":{"_id":{"$oid":"61530ff10eae08c91a0f0794"},"username":"oleg1"}, "createdAt":{"$date":"2021-09-28T13:12:41.335Z"}, "_id":{"$oid":"615314c9ba504ed1f92af7a4"}}, "content":" orange apple" }
我使用TypeORM / Nest.JS的service进行查询,代码如下:
async getGraphOfContext(contextId: string, maxNodes = 150, addStats = false) { const context: Context = await this.contextRepository.findOne(contextId, { relations: ['statements', 'user'], }); console.log(context); }
但最终仅返回如下内容:
Context { _id: 615314c9ba504ed1f92af7a7, contextName: 'luchkas1', createdAt: 2021-09-28T13:12:41.335Z }
与context关联的用户id及statements内容都未返回,相同的TypeORM配置在PostgreSQL中运行正常。
问题根因
- TypeORM的
relations配置仅面向PostgreSQL、MySQL这类关系型数据库的外键关联场景设计,MongoDB属于文档型数据库,你需要的statements、user是文档内部的嵌套字段,不属于跨表外键关联,因此relations参数不会生效。 - 你当前存储的
statements、user都嵌套在文档内的context子对象中,若你的Context实体没有正确映射嵌套字段的层级结构,也会导致查询后无法读取对应属性。 - 你存储的文档存在重复
_id字段(顶层一个,context子对象内还有一个),属于不规范的结构,虽然不直接影响查询,但可能引发实体映射异常,建议后续清理。
修复方案
方案1:调整实体映射适配MongoDB嵌套结构
使用TypeORM MongoDB版本提供的嵌套文档装饰器,正确映射你当前的存储结构:
// 定义嵌套的User子实体 import { Embeddable, Property, ObjectIdColumn, ObjectID } from '@typeorm/mongodb'; @Embeddable() export class ContextUser { @ObjectIdColumn() _id: ObjectID; @Property() username: string; } // 定义context子文档实体 @Embeddable() class ContextSubDoc { @Property() contextName: string; @Property() statements: any[]; // 可按业务实际替换为对应声明类型 @Column(() => ContextUser) user: ContextUser; @Property() createdAt: Date; @ObjectIdColumn() _id: ObjectID; } // 主Context实体 import { Entity, ObjectIdColumn, ObjectID, Column, Property } from '@typeorm/mongodb'; @Entity() export class Context { @ObjectIdColumn() _id: ObjectID; // 映射嵌套的context子对象 @Column(() => ContextSubDoc) context: ContextSubDoc; @Property() content: string; // 可选:添加快捷getter和你之前的使用逻辑对齐 get contextName() { return this.context.contextName; } get statements() { return this.context.statements; } get user() { return this.context.user; } get createdAt() { return this.context.createdAt; } }
调整后不需要添加relations参数,直接查询即可拿到完整嵌套内容:
async getGraphOfContext(contextId: string, maxNodes = 150, addStats = false) { const context: Context = await this.contextRepository.findOne(contextId); console.log(context.statements, context.user); }
方案2:直接调用MongoDB原生查询
如果不想调整现有实体结构,可以直接调用TypeORM封装的MongoDB原生查询能力,不需要依赖实体映射规则:
import { ObjectID } from 'mongodb'; async getGraphOfContext(contextId: string, maxNodes = 150, addStats = false) { const objectId = new ObjectID(contextId); const context = await this.contextRepository.findOneBy({ _id: objectId }); // 直接通过原生文档结构访问嵌套字段 console.log(context.context.statements, context.context.user); }
优化建议
如果业务允许,建议把contextName、statements、user、createdAt这些字段挪到文档顶层,不需要额外套一层context对象,减少嵌套层级,也能和你之前PostgreSQL的结构对齐,降低实体适配成本。
内容的提问来源于stack exchange,提问作者Aerodynamika
相关产品推荐
相关产品推荐

