与 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 callingMikroORM.init<D>()
. Alternatively we can cast theorm.em
toEntityManager
exported from the driver package:import { EntityManager } from '@mikro-orm/mongodb';
const em = orm.em as EntityManager;
const qb = em.aggregate(...);
我们需要使用
clientUrl
来设置主机,不支持使用host
或port
。¥We need to use
clientUrl
to set up hosts, usinghost
orport
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: ObjectId
。id: 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
每个实体都有可用的 ObjectId
和 string
id,而且 EntityManager
和 EntityRepository
的所有方法都支持两者的查询。
¥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:
-
集合存储在拥有方实体上,因此我们在初始化集合之前就知道有多少个项目。
¥Collection is stored on owning side entity, so we know how many items are there even before initializing the collection.
-
由于没有数据透视表,因此产生的数据库查询要简单得多。
¥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[]>;