首页
/ TypeORM MongoDB 驱动实战:连接选项全解、内嵌文档建模与 MongoRepository 高级查询

TypeORM MongoDB 驱动实战:连接选项全解、内嵌文档建模与 MongoRepository 高级查询

2026-09-05 11:09:27作者:平淮齐Percy

TypeORM 对 MongoDB 提供基础但完整的文档数据库支持(要求 MongoDB Node.js 驱动 v7 或更高版本),本篇基于官方驱动文档 mongodb.md 与当前仓库源码,系统梳理 MongoDB 支持的适用边界、全部 Data Source 连接选项、@ObjectIdColumn 与内嵌文档建模方式,以及 MongoEntityManager / MongoRepository 的高级查询能力。读完后你能够:正确配置 MongoDB 数据源连接、用 TypeORM 实体语法建模文档与子文档,并熟练使用 MongoDB 原生查询运算符与集合级方法。

一、MongoDB 支持边界:哪些功能可用、哪些不可用

官方文档开宗明义:TypeORM 具有基础的 MongoDB 支持,而 TypeORM 的大多数功能是面向关系型数据库(RDBMS)的,MongoDB 页面只涵盖 MongoDB 专属功能。这个边界在驱动源码 MongoDriver.ts 中有清晰的自述:

此外,MongoRepository 对 RDBMS 专属方法做了显式禁用:

// 来自 src/repository/MongoRepository.ts
query(query: string, parameters?: any[]): Promise<any> {
    throw new TypeORMError(`Queries aren't supported by MongoDB.`)
}

createQueryBuilder(alias: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity> {
    throw new TypeORMError(`Query Builder is not supported by MongoDB.`)
}

src/repository/MongoRepository.ts#L73-L89。也就是说:query() 原生查询、Query Builder、事务在 MongoDB 连接上一律不可用,这正是文档所说 "except for RDBMS-specific, like query and transaction" 的源码依据。

二、安装

安装官方 MongoDB Node.js 驱动即可:

npm install mongodb

加载逻辑在 src/driver/mongodb/MongoDriver.ts#L550-L557

protected loadDependencies(): any {
    try {
        const mongodb = this.options.driver ?? PlatformTools.load("mongodb")
        this.mongodb = mongodb
    } catch (e) {
        throw new DriverPackageNotInstalledError("MongoDB", "mongodb")
    }
}

两个要点:

  1. 默认通过 PlatformTools.load("mongodb") 动态加载 mongodb 包,未安装时抛出 DriverPackageNotInstalledErrorDriverPackageNotInstalledError.ts);
  2. 可以在 DataSource 选项中直接传入 driver 对象(默认 require("mongodb")),便于替换或锁定驱动版本。

三、Data Source 连接选项全解

MongoDB 的 DataSource 选项定义在 src/driver/mongodb/MongoDataSourceOptions.ts,与官方 MongoDB Node 驱动的 MongoClientOptions 保持同步。完整选项清单如下(与文档一致,含默认值说明):

3.1 连接基础选项

选项 说明
url 连接 URL。注意:其他 DataSource 选项会覆盖 URL 中设置的同名参数
host 数据库主机。源码中默认 127.0.0.1
hostReplicaSet 副本集的主机地址(配置了 replicaSet 时优先生效)
port 主机端口,MongoDB 默认 27017
username 数据库用户名
password 数据库密码
database 数据库名
driver 驱动对象,默认 require("mongodb")
family IP 族(IPv4/IPv6)
directConnection 强制单主机连接串使用 Single 拓扑

3.2 认证、TLS 与自动加密

选项 说明
authMechanism MongoDB 使用的认证机制
authSource 用户凭据关联的数据库名
tls 启用/禁用 TLS/SSL,默认 false
tlsAllowInvalidCertificates 跳过证书验证,默认 false
tlsCAFile 根证书链 .pem 文件路径
tlsCertificateKeyFile 客户端 TLS 证书与密钥 .pem 文件路径
tlsCertificateKeyFilePassword 解密 tlsCertificateKeyFile 的密码
checkServerIdentity 校验证书 cert 是否签发给了 hostname
autoEncryption 启用 in-use 自动加密(可选)

3.3 连接池、超时与网络

选项 说明
connectTimeoutMS 建连超时(毫秒),默认 30000
socketTimeoutMS socket 收发超时(毫秒),默认 360000
localThresholdMS 多实例延迟选择窗口(毫秒)
minPoolSize 连接池最小连接数
poolSize 连接池最大连接数,映射为 MongoDB 驱动的 maxPoolSize
noDelay TCP no delay
compressors 网络压缩器,数组或逗号分隔字符串
retryWrites 启用可重试写入
monitorCommands 启用命令监控

3.4 副本集与读写偏好

选项 说明
replicaSet 副本集名称(mongod 属于副本集时指定)
maxStalenessSeconds 从节点允许的最大滞后时间(秒),最小 90 秒
readConcern 集合的读关注级别
readPreference 读偏好,取值:ReadPreference.PRIMARYPRIMARY_PREFERREDSECONDARYSECONDARY_PREFERREDNEAREST
readPreferenceTags 以冒号分隔的键值对逗号列表指定标签文档
writeConcern 写关注级别,描述写操作的确认程度

3.5 BSON 序列化与 _id 行为

选项 说明
forceServerObjectId 强制由服务端分配 _id,默认 false
ignoreUndefined BSON 序列化器是否忽略 undefined 字段,默认 false
promoteBuffers 将 Binary BSON 值提升为 Node Buffer,默认 false
promoteLongs 在 53 位精度内将 Long 提升为 number,默认 true
promoteValues 尽可能将 BSON 值提升为原生类型,默认 true
raw 以原始 BSON buffer 返回结果,默认 false
serializeFunctions 是否序列化对象中的函数,默认 false
pkFactory 自定义 _id 主键工厂对象

3.6 Socks5 代理

选项 说明
proxyHost Socks5 代理主机
proxyPort Socks5 代理端口
proxyUsername Socks5 代理用户名
proxyPassword Socks5 代理密码

extra 透传机制:文档还指出,其余选项可以放进 extra 对象,会被直接传递给客户端库。这一点在 src/driver/mongodb/MongoDriver.ts#L592-L612 中得到印证——buildConnectionOptions 先按白名单 validOptionNames 逐项复制已知选项,再把 options.extra 整体合并:

protected buildConnectionOptions(options: { [key: string]: any }): any {
    const mongoOptions: any = {}
    for (const optionName of this.validOptionNames) {
        if (optionName in options) {
            mongoOptions[optionName] = options[optionName]
        }
    }
    mongoOptions.driverInfo = { name: "TypeORM" }
    if ("poolSize" in options) {
        mongoOptions["maxPoolSize"] = options["poolSize"]
    }
    Object.assign(mongoOptions, options.extra)
    return mongoOptions
}

从源码结构看还有两个实用细节:连接串由 buildConnectionUrl 拼装,mongodb+srv 类型不拼接端口;配置了 replicaSet 时优先使用 hostReplicaSet 作为主机段;客户端会携带 driverInfo: { name: "TypeORM" } 便于在 MongoDB 服务端识别来源。

3.7 应用引导示例

import { DataSource } from "typeorm"

const myDataSource = new DataSource({
    type: "mongodb",
    host: "localhost",
    port: 27017,
    database: "test",
})

调用 await myDataSource.initialize() 后,MongoDriver.connect 会执行 MongoClient.connect(url, options) 并创建唯一的 MongoQueryRunner——MongoDB 没有 RDBMS 那样的连接池概念,因此驱动实例只持有一个查询执行器(src/driver/mongodb/MongoDriver.ts#L57-L61)。

四、定义实体与列:@ObjectIdColumn

MongoDB 实体定义与关系型数据库几乎相同,核心区别是:必须使用 @ObjectIdColumn() 代替 @PrimaryColumn@PrimaryGeneratedColumn

import { ObjectId } from "mongodb"
import { Entity, ObjectIdColumn, Column } from "typeorm"

@Entity()
export class User {
    @ObjectIdColumn()
    _id: ObjectId

    @Column()
    firstName: string

    @Column()
    lastName: string
}

ObjectIdColumn.ts 的实现揭示了它的本质——它只是带特殊元数据模式的普通列:

export function ObjectIdColumn(options?: ColumnOptions): PropertyDecorator {
    return function (object: Object, propertyName: string) {
        options ??= {} as ColumnOptions
        options.primary = true      // 强制为主键
        options.name ??= "_id"     // 数据库字段名默认 _id
        getMetadataArgsStorage().columns.push({
            target: object.constructor,
            propertyName: propertyName,
            mode: "objectId",      // MongoDB 专属列模式
            options: options,
        } as ColumnMetadataArgs)
    }
}

src/decorator/columns/ObjectIdColumn.ts#L11-L25。两个实用推论:

  • 属性名可以任意命名(如 id 而非 _id),TypeORM 在查询条件中会自动把实体属性名重写为数据库的 _id,并把字符串等标量转换为 ObjectId 实例。这一机制实现在 MongoEntityManager.replaceObjectIdProperty,会递归处理 $or/$and 嵌套条件;
  • 写入侧的 update/delete 等混合条件经 convertMixedCriteria 归一化:ObjectId.isValid 兼容的字符串、数字、Buffer 或 ObjectId 都会转换为 { _id: new ObjectId(...) } 查询。

五、定义子文档(内嵌文档)

MongoDB 存储"对象中的对象",TypeORM 允许用不带 @Entity() 的普通类作为列类型,通过 @Column((type) => Class) 声明内嵌文档。

export class Profile {
    @Column()
    about: string

    @Column()
    education: string

    @Column()
    career: string
}

export class Photo {
    @Column()
    url: string

    @Column()
    description: string

    @Column()
    size: number

    constructor(url: string, description: string, size: number) {
        this.url = url
        this.description = description
        this.size = size
    }
}

@Entity()
export class User {
    @ObjectIdColumn()
    id: ObjectId

    @Column()
    firstName: string

    @Column()
    lastName: string

    @Column((type) => Profile)
    profile: Profile

    @Column((type) => Photo)
    photos: Photo[]
}

保存该实体:

const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.profile = new Profile()
user.profile.about = "About Trees and Me"
user.profile.education = "Tree School"
user.profile.caret = "Lumberjack"
user.photos = [
    new Photo("me-and-trees.jpg", "Me and Trees", 100),
    new Photo("me-and-chakram.jpg", "Me and Chakram", 200),
]

await myDataSource.manager.save(user)

数据库中实际存储的文档为(单条嵌套文档,内嵌文档数组被整体序列化):

{
    "firstName": "Timber",
    "lastName": "Saw",
    "profile": {
        "about": "About Trees and Me",
        "education": "Tree School",
        "career": "Lumberjack"
    },
    "photos": [
        {
            "url": "me-and-trees.jpg",
            "description": "Me and Trees",
            "size": 100
        },
        {
            "url": "me-and-chakram.jpg",
            "description": "Me and Chakram",
            "size": 200
        }
    ]
}

六、用 select 投影指定字段

find* 方法的 select 选项被翻译为 MongoDB 的 projection,嵌套内嵌文档使用对象语法并扁平化为点路径投影:

const products = await myDataSource.getMongoRepository(Product).find({
    select: { name: true, specs: { weight: true } },
})

上述示例只返回每个产品的 namespecs.weight(外加实体 id)。翻译逻辑在 MongoEntityManager.convertFindOptionsSelectToProjectCriteria

  • 普通列直接映射为 projection["列路径"] = 1
  • 内嵌文档写 true 时展开其全部列(columnsFromTree),写对象时递归展开为点路径;
  • 未知属性名(无论顶层还是内嵌层)抛出 EntityPropertyNotFoundErrorsrc/error/EntityPropertyNotFoundError.ts),与 SQL 驱动行为一致;
  • 若实体主键属性名不是 _id(如 id),投影会自动重写为 _id

七、MongoEntityManagerMongoRepository

MongoEntityManager 继承自 EntityManagersrc/entity-manager/MongoEntityManager.ts),EntityManager 的大多数方法均可使用(除 RDBMS 专属的 querytransaction)。例如:

const timber = await myDataSource.manager.findOneBy(User, {
    firstName: "Timber",
    lastName: "Saw",
})

与 RDBMS 的 Repository 对应,MongoDB 有扩展的 MongoRepository,通过 DataSource.getMongoRepository() 获取(src/data-source/DataSource.ts#L464-L470,非 MongoDB 连接调用会抛出 "You can use getMongoRepository only for MongoDB connections."):

const timber = await myDataSource.getMongoRepository(User).findOneBy({
    firstName: "Timber",
    lastName: "Saw",
})

7.1 find() 中使用 MongoDB 原生查询运算符

MongoRepository.find()where 直接接受 MongoDB 查询语法(对应类型见 src/find-options/mongodb/MongoFindManyOptions.ts):

等值匹配:

const timber = await myDataSource.getMongoRepository(User).find({
    where: {
        firstName: { $eq: "Timber" },
    },
})

小于:

const timber = await myDataSource.getMongoRepository(User).find({
    where: {
        age: { $lt: 60 },
    },
})

In:

const timber = await myDataSource.getMongoRepository(User).find({
    where: {
        firstName: { $in: ["Timber", "Zhang"] },
    },
})

Not In:

const timber = await myDataSource.getMongoRepository(User).find({
    where: {
        firstName: { $not: { $in: ["Timber", "Zhang"] } },
    },
})

Or:

const timber = await myDataSource.getMongoRepository(User).find({
    where: {
        $or: [{ firstName: "Timber" }, { firstName: "Zhang" }],
    },
})

查询子文档——用点路径访问内嵌字段:

const users = await myDataSource.getMongoRepository(User).find({
    where: {
        "profile.education": { $eq: "Tree School" },
    },
})

查询子文档数组——点路径对数组自动做元素级匹配(查询拥有 size 小于 500 照片的用户):

const users = await myDataSource.getMongoRepository(User).find({
    where: {
        "photos.size": { $lt: 500 },
    },
})

从源码结构看,find 的完整执行链路是:where 条件经 convertFindManyOptionsOrConditionsToMongodbQuery 转换(字符串形式的 SQL where 会被忽略,因为 MongoDB 不是 SQL 数据库),再经 replaceObjectIdProperty 重写主键条件,最后交给 createEntityCursor 构建游标;skipcursor.skip()takecursor.limit()order 中的 ASC/DESC 分别转换为 1/-1 传给 cursor.sort()convertFindOptionsOrderToOrderCriteria)。游标结果通过 DocumentToEntityTransformer 自动还原为实体,并在 toArray/next 上广播 Load 事件以触发订阅者(applyEntityTransformationToCursor)。若实体配置了软删除列,查询会自动追加 deleteDate $eq null 过滤条件(filterSoftDeleted),除非显式指定 withDeleted

7.2 MongoDB 专属方法一览

MongoEntityManagerMongoRepository 都提供大量 MongoDB 专属方法,当前仓库源码中实际实现的清单如下(均以"实体类/实体名 + 原始 MongoDB 参数"的形式透传给 MongoQueryRunner):

方法 说明
createCursor 创建查询游标,用于迭代 MongoDB 结果
createEntityCursor 创建游标并将每条结果自动转换为实体模型
aggregate / aggregateEntity 对集合执行聚合管道;aggregateEntity 将结果转换为实体
bulkWrite 不使用流式 API 的批量写入操作
count / countDocuments / countBy 统计匹配查询的文档数量
createCollectionIndex 在集合上创建索引
createCollectionIndexes 一次创建多个索引(MongoDB 2.6+)
collectionIndexes 获取集合全部索引
collectionIndexExists 判断集合上是否存在指定索引
collectionIndexInformation 获取集合的索引信息
dropCollectionIndex 删除集合上的一个索引
dropCollectionIndexes 删除集合上的所有索引
deleteMany / deleteOne 删除多个/单个文档
distinct 返回某键在集合中所有不重复的值
findOneAndDelete 原子地查找并删除文档(操作期间持有写锁)
findOneAndReplace 原子地查找并替换文档
findOneAndUpdate 原子地查找并更新文档
initializeOrderedBulkOp 有序批量写:按添加顺序串行执行
initializeUnorderedBulkOp 无序批量写:缓冲后乱序执行
insertMany / insertOne 插入文档数组 / 单个文档
isCapped 判断集合是否为 capped 集合
listCollectionIndexes 获取集合索引信息列表(游标)
rename 重命名现有集合
replaceOne 替换一个文档
updateMany / updateOne 按过滤条件更新多个/单个文档
watch 创建 Change Stream 监听集合变更

需要说明的是:官方文档的方法清单中还列出了 geoHaystackSearchgeoNeargroupparallelCollectionScanreIndex 等条目,但在当前仓库的 MongoEntityManagerMongoRepository 源码中已检索不到这些方法。从源码结构看,它们是 MongoDB 官方 Node 驱动升级(v7)后从 Collection API 中移除的历史方法,文档尚未同步清理——实际使用时请以当前源码方法清单为准。

八、小结:验证与适用前提

  • 适用前提type: "mongodb" 的 DataSource、MongoDB Node.js 驱动 v7+;连接参数以 MongoDataSourceOptions.ts 的类型定义为准,extra 可透传其余 MongoClientOptions
  • 不可用能力:事务与隔离级别、Query Builder、query() 原生 SQL、schema 同步、树形实体、CTE;
  • 建模要点@ObjectIdColumn 强制主键且默认映射 _id;内嵌文档用 @Column((type) => X) 声明,查询用点路径;
  • 功能验证:仓库在 test/functional/mongodb/ 目录下维护了 30 余个功能测试(内嵌文档、查询运算符、游标、索引等),可作为各特性真实行为的参照;本文所有连接拼装、选项白名单、投影与游标转换结论均可在 src/driver/mongodb/src/entity-manager/MongoEntityManager.ts 中逐行核对。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384