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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 09:57:05