Skip to main content
Version: 6.4

与 MongoDB 一起使用

要将 MikroORM 与 mongo 数据库一起使用,请不要忘记安装 @mikro-orm/mongodb 依赖。然后在引导应用时调用 MikroORM.init()

¥To use MikroORM with mongo database, do not forget to install @mikro-orm/mongodb dependency. Then call MikroORM.init() as part of bootstrapping your app:

要访问驱动程序特定方法(如 em.aggregate()),我们需要在调用 MikroORM.init<D>() 时指定驱动程序类型。或者,我们可以将 orm.em 转换为从驱动程序包导出的 EntityManager

¥To access driver specific methods like em.aggregate() we need to specify the driver type when calling MikroORM.init<D>(). Alternatively we can cast the orm.em to EntityManager exported from the driver package:

import { EntityManager } from '@mikro-orm/mongodb';
const em = orm.em as EntityManager;
const qb = em.aggregate(...);

我们需要使用 clientUrl 来设置主机,不支持使用 hostport

¥We need to use clientUrl to set up hosts, using host or port is not supported.

import { MikroORM } from '@mikro-orm/mongodb'; // or any other driver package

const orm = await MikroORM.init({
entities: [Author, Book, ...],
dbName: 'my-db-name',
clientUrl: '...',
});
console.log(orm.em); // access EntityManager via `em` property

定义实体

¥Defining entity

定义实体时,请不要忘记定义主键,如下所示:

¥When defining entity, do not forget to define primary key like this:

@PrimaryKey()
_id: ObjectId;

@SerializedPrimaryKey()
id!: string; // won't be saved in the database

数据库中只保存 _id: ObjectIdid: string 是虚拟的,也是可选的。

¥Only _id: ObjectId will be saved in the database. id: string is virtual and is also optional.

ObjectId 和字符串 id 二元性

¥ObjectId and string id duality

每个实体都有可用的 ObjectIdstring id,而且 EntityManagerEntityRepository 的所有方法都支持两者的查询。

¥Every entity has both ObjectId and string id available, also all methods of EntityManager and EntityRepository supports querying by both of them.

const author = orm.em.getReference('...id...');
console.log(author.id); // returns '...id...'
console.log(author._id); // returns ObjectId('...id...')

// all of those will return the same results
const article = '...article id...'; // string id
const book = '...book id...'; // string id
const repo = orm.em.getRepository(Author);
const foo1 = await repo.find({ id: { $in: [article] }, favouriteBook: book });
const bar1 = await repo.find({ id: { $in: [new ObjectId(article)] }, favouriteBook: new ObjectId(book) });
const foo2 = await repo.find({ _id: { $in: [article] }, favouriteBook: book });
const bar2 = await repo.find({ _id: { $in: [new ObjectId(article)] }, favouriteBook: new ObjectId(book) });

带有内联枢轴数组的多对多集合

¥ManyToMany collections with inlined pivot array

与使用数据透视表的 SQL 驱动程序相反,在 mongo 中,我们可以利用可用的数组类型来存储集合项(标识符)的数组。这种方法有两个主要好处:

¥As opposed to SQL drivers that use pivot tables, in mongo we can leverage available array type to store array of collection items (identifiers). This approach has two main benefits:

  1. 集合存储在拥有方实体上,因此我们在初始化集合之前就知道有多少个项目。

    ¥Collection is stored on owning side entity, so we know how many items are there even before initializing the collection.

  2. 由于没有数据透视表,因此产生的数据库查询要简单得多。

    ¥As there are no pivot tables, resulting database queries are much simpler.

事务

¥Transactions

从 v3.4 开始,MongoDB 驱动程序支持事务。要使用事务,你需要注意以下几点:

¥Starting with v3.4, MongoDB driver supports transactions. To use transactions, there are several things you need to respect:

  • 你需要使用副本集(参见 run-rs

    ¥you need to use replica set (see run-rs)

  • 默认情况下禁用隐式事务

    ¥implicit transactions are disabled by default

    • 使用 implicitTransactions: true 全局启用它们

      ¥use implicitTransactions: true to enable them globally

    • 或通过 em.transactional() 使用显式事务划分

      ¥or use explicit transaction demarcation via em.transactional()

  • 你需要在使用它们之前明确创建所有集合

    ¥you need to explicitly create all collections before working with them

    • 使用 orm.schema.createSchema() 方法来执行此操作

      ¥use orm.schema.createSchema() method to do so

# first create replica set
$ run-rs -v 4.2.3
// make sure to import from the MongoDriver package
import { MikroORM } from '@mikro-orm/mongodb';

const orm = await MikroORM.init({
entities: [Author, Book, ...],
clientUrl: 'mongodb://localhost:27017,localhost:27018,localhost:27019/my-db-name?replicaSet=rs0',
implicitTransactions: true, // defaults to false
});

await orm.schema.createSchema();

索引

¥Indexes

从 v3.4 开始,MongoDB 驱动程序支持索引和唯一约束。你可以按照 定义实体部分 中所述使用 @Index()@Unique()。要在初始化 ORM 时自动创建新索引,你需要启用 ensureIndexes 选项。

¥Starting with v3.4, MongoDB driver supports indexes and unique constraints. You can use @Index() and @Unique() as described in Defining Entities section. To automatically create new indexes when initializing the ORM, you need to enable ensureIndexes option.

const orm = await MikroORM.init({
entities: [Author, Book, ...],
dbName: 'my-db-name',
ensureIndexes: true, // defaults to false
});

或者,你可以在 SchemaGenerator 上调用 ensureIndexes() 方法:

¥Alternatively you can call ensureIndexes() method on the SchemaGenerator:

SchemaGenerator 对 mongo 的支持是在 v5 中引入的。

¥SchemaGenerator support for mongo was introduced in v5.

await orm.schema.ensureIndexes();

你可以通过 options 参数传递其他索引/唯一选项:

¥You can pass additional index/unique options via options parameter:

@Unique({ options: { partialFilterExpression: { name: { $exists: true } } }})

你还可以通过传递 type 参数来创建文本索引:

¥You can also create text indexes by passing type parameter:

@Index({ properties: ['name', 'caption'], type: 'text' })

如果你在索引定义中仅提供 options,它将按原样使用,这允许定义任何类型的索引:

¥If you provide only options in the index definition, it will be used as is, this allows to define any kind of index:

@Index({ options: { point: '2dsphere', title: -1 } })

要设置索引权重,你可以将元组传递给 options 参数:

¥To set index weights, you can pass a tuple to the options parameter:

@Index({ options: [
{ title: 'text', perex: 'text', key: 1 },
{ weights: { title: 10, perex: 5 } },
] })

原生集合方法

¥Native collection methods

有时你需要执行一些批量操作,或者你只想用初始装置填充数据库。使用 ORM 进行此类操作可能会带来不必要的样板代码。在这种情况下,你可以使用 insert/nativeUpdate/nativeDelete 方法之一:

¥Sometimes you need to perform some bulk operation, or you just want to populate your database with initial fixtures. Using ORM for such operations can bring unnecessary boilerplate code. In this case, you can use one of insert/nativeUpdate/nativeDelete methods:

em.insert<T extends AnyEntity>(entityName: string, data: any): Promise<IPrimaryKey>;
em.nativeUpdate<T extends AnyEntity>(entityName: string, where: FilterQuery<T>, data: any): Promise<number>;
em.nativeDelete<T extends AnyEntity>(entityName: string, where: FilterQuery<T> | any): Promise<number>;

这些方法分别执行原生驱动程序方法,如 Mongo 的 insertOne/updateMany/deleteMany 集合方法。这是所有驱动程序的通用接口,因此对于 MySQL 驱动程序,它将触发原生 SQL 查询。请记住,它们不会将结果水合到实体中,也不会触发生命周期钩子。

¥Those methods execute native driver methods like Mongo's insertOne/updateMany/deleteMany collection methods respectively. This is common interface for all drivers, so for MySQL driver, it will fire native SQL queries. Keep in mind that they do not hydrate results to entities, and they do not trigger lifecycle hooks.

它们也可用作 EntityRepository 快捷方式:

¥They are also available as EntityRepository shortcuts:

EntityRepository.insert(data: any): Promise<IPrimaryKey>;
EntityRepository.nativeUpdate(where: FilterQuery<T>, data: any): Promise<number>;
EntityRepository.nativeDelete(where: FilterQuery<T> | any): Promise<number>;

还有调用 aggregate 方法的快捷方式:

¥There is also shortcut for calling aggregate method:

em.aggregate(entityName: string, pipeline: any[]): Promise<any[]>;
EntityRepository.aggregate(pipeline: any[]): Promise<any[]>;