@mikro-orm/mongodb 7.1.0-dev.1 → 7.1.0-dev.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/MongoDriver.d.ts CHANGED
@@ -15,11 +15,13 @@ export declare class MongoDriver extends DatabaseDriver<MongoConnection> {
15
15
  rawResults?: boolean;
16
16
  }): AsyncIterableIterator<T>;
17
17
  find<T extends object, P extends string = never, F extends string = never, E extends string = never>(entityName: EntityName<T>, where: FilterQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
18
+ private findWithPartitionLimit;
18
19
  findOne<T extends object, P extends string = never, F extends string = never, E extends string = never>(entityName: EntityName<T>, where: FilterQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
19
20
  findVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
20
21
  streamVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): AsyncIterableIterator<EntityData<T>>;
21
22
  count<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options?: CountOptions<T>): Promise<number>;
22
23
  nativeInsert<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
24
+ nativeClone<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, overrides?: EntityData<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
23
25
  nativeInsertMany<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
24
26
  nativeUpdate<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T> & UpsertOptions<T>): Promise<QueryResult<T>>;
25
27
  nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateOptions<T> & UpsertManyOptions<T>): Promise<QueryResult<T>>;
@@ -30,7 +32,8 @@ export declare class MongoDriver extends DatabaseDriver<MongoConnection> {
30
32
  streamAggregate<T extends object>(entityName: EntityName<T>, pipeline: any[], ctx?: Transaction<ClientSession>): AsyncIterableIterator<T>;
31
33
  getPlatform(): MongoPlatform;
32
34
  private buildQueryOptions;
33
- private renameFields;
35
+ /** @internal */
36
+ renameFields<T extends object>(entityName: EntityName<T>, data: T, dotPaths?: boolean, object?: boolean, root?: boolean): T;
34
37
  private convertObjectIds;
35
38
  private buildFilterById;
36
39
  protected buildFields<T extends object, P extends string = never>(entityName: EntityName<T>, populate: PopulateOptions<T>[], fields?: readonly EntityField<T, P>[], exclude?: string[]): string[] | undefined;
package/MongoDriver.js CHANGED
@@ -78,6 +78,10 @@ export class MongoDriver extends DatabaseDriver {
78
78
  return res.map(r => this.mapResult(r, this.metadata.find(entityName)));
79
79
  }
80
80
  const orderBy = Utils.asArray(options.orderBy).map(orderBy => this.renameFields(entityName, orderBy, true));
81
+ const partitionLimit = options._partitionLimit;
82
+ if (partitionLimit) {
83
+ return this.findWithPartitionLimit(entityName, where, orderBy, fields ?? [], partitionLimit, options);
84
+ }
81
85
  const res = await this.rethrow(this.getConnection('read').find(entityName, where, {
82
86
  orderBy,
83
87
  limit: options.limit,
@@ -88,6 +92,48 @@ export class MongoDriver extends DatabaseDriver {
88
92
  }));
89
93
  return res.map(r => this.mapResult(r, this.metadata.find(entityName)));
90
94
  }
95
+ async findWithPartitionLimit(entityName, where, orderBy, fields, partitionLimit, options) {
96
+ const meta = this.metadata.find(entityName);
97
+ const { limit, offset = 0 } = partitionLimit;
98
+ // Resolve the partition property to its DB field name; callers always pass
99
+ // a declared property on the target meta (FK of the owning side).
100
+ const prop = meta.properties[partitionLimit.partitionBy];
101
+ const partitionField = prop.fieldNames[0];
102
+ const pipeline = [];
103
+ pipeline.push({ $match: where });
104
+ if (orderBy.length > 0) {
105
+ const sortSpec = {};
106
+ for (const order of orderBy) {
107
+ for (const [key, dir] of Object.entries(order)) {
108
+ sortSpec[key] = dir === 'ASC' || dir === 'asc' || dir === 1 ? 1 : -1;
109
+ }
110
+ }
111
+ pipeline.push({ $sort: sortSpec });
112
+ }
113
+ // $sort before $group ensures $push collects in correct order
114
+ pipeline.push({
115
+ $group: {
116
+ _id: `$${partitionField}`,
117
+ __docs: { $push: '$$ROOT' },
118
+ },
119
+ });
120
+ pipeline.push({
121
+ $project: {
122
+ __docs: { $slice: ['$__docs', offset, limit] },
123
+ },
124
+ });
125
+ pipeline.push({ $unwind: '$__docs' });
126
+ pipeline.push({ $replaceRoot: { newRoot: '$__docs' } });
127
+ if (fields.length > 0) {
128
+ const projection = {};
129
+ for (const field of fields) {
130
+ projection[field] = 1;
131
+ }
132
+ pipeline.push({ $project: projection });
133
+ }
134
+ const res = await this.rethrow(this.getConnection('read').aggregate(entityName, pipeline, options.ctx, options.logging));
135
+ return res.map(r => this.mapResult(r, meta));
136
+ }
91
137
  async findOne(entityName, where, options = { populate: [], orderBy: {} }) {
92
138
  if (this.metadata.find(entityName)?.virtual) {
93
139
  const [item] = await this.findVirtual(entityName, where, options);
@@ -148,6 +194,27 @@ export class MongoDriver extends DatabaseDriver {
148
194
  data = this.renameFields(entityName, data);
149
195
  return this.rethrow(this.getConnection('write').insertOne(entityName, data, options.ctx));
150
196
  }
197
+ async nativeClone(entityName, where, overrides, options = {}) {
198
+ const meta = this.metadata.find(entityName);
199
+ const pk = meta.getPrimaryProps()[0].fieldNames[0] ?? '_id';
200
+ const normalizedWhere = Utils.isPrimaryKey(where) ? { [pk]: where } : where;
201
+ const renameWhere = this.renameFields(entityName, normalizedWhere);
202
+ const source = await this.rethrow(this.getConnection('read').find(entityName, renameWhere, { ctx: options.ctx, limit: 1 }));
203
+ if (!source.length) {
204
+ throw new Error('Cannot clone: no entity found matching the given condition');
205
+ }
206
+ const doc = source[0];
207
+ delete doc[pk];
208
+ if (overrides) {
209
+ const mapped = this.renameFields(entityName, overrides);
210
+ Object.assign(doc, mapped);
211
+ }
212
+ if (meta.versionProperty) {
213
+ const vProp = meta.properties[meta.versionProperty];
214
+ doc[vProp.fieldNames[0]] = vProp.runtimeType === 'Date' ? new Date() : 1;
215
+ }
216
+ return this.rethrow(this.getConnection('write').insertOne(entityName, doc, options.ctx));
217
+ }
151
218
  async nativeInsertMany(entityName, data, options = {}) {
152
219
  data = data.map(item => {
153
220
  this.handleVersionProperty(entityName, item);
@@ -247,6 +314,13 @@ export class MongoDriver extends DatabaseDriver {
247
314
  if (options.indexHint != null) {
248
315
  ret.indexHint = options.indexHint;
249
316
  }
317
+ else if (options.using != null) {
318
+ const names = Utils.asArray(options.using);
319
+ if (names.length > 1) {
320
+ throw new Error('MongoDB only supports a single index hint per query. Provide one index name instead of an array.');
321
+ }
322
+ ret.indexHint = names[0];
323
+ }
250
324
  if (options.maxTimeMS != null) {
251
325
  ret.maxTimeMS = options.maxTimeMS;
252
326
  }
@@ -255,6 +329,7 @@ export class MongoDriver extends DatabaseDriver {
255
329
  }
256
330
  return ret;
257
331
  }
332
+ /** @internal */
258
333
  renameFields(entityName, data, dotPaths = false, object, root = true) {
259
334
  if (data == null && root) {
260
335
  return {};
@@ -1,4 +1,4 @@
1
- import { EntityManager, type EntityName, type EntityRepository, type GetRepository, type TransactionOptions, type StreamOptions, type Loaded } from '@mikro-orm/core';
1
+ import { EntityManager, type CountByOptions, type Dictionary, type EntityKey, type EntityName, type EntityRepository, type GetRepository, type Loaded, type StreamOptions, type TransactionOptions, type WithUsingOptions } from '@mikro-orm/core';
2
2
  import type { Collection, Document, TransactionOptions as MongoTransactionOptions } from 'mongodb';
3
3
  import type { MongoDriver } from './MongoDriver.js';
4
4
  import type { MongoEntityRepository } from './MongoEntityRepository.js';
@@ -17,8 +17,12 @@ export declare class MongoEntityManager<Driver extends MongoDriver = MongoDriver
17
17
  /**
18
18
  * @inheritDoc
19
19
  */
20
- stream<Entity extends object, Hint extends string = never, Fields extends string = never, Excludes extends string = never>(entityName: EntityName<Entity>, options?: StreamOptions<NoInfer<Entity>, Hint, Fields, Excludes>): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
20
+ stream<Entity extends object, Hint extends string = never, Fields extends string = never, Excludes extends string = never, Using extends string = never>(entityName: EntityName<Entity>, options?: WithUsingOptions<StreamOptions<NoInfer<Entity>, Hint, Fields, Excludes>, NoInfer<Entity>, Using>): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
21
21
  getCollection<T extends Document>(entityOrCollectionName: EntityName<T> | string): Collection<T>;
22
+ /**
23
+ * @inheritDoc
24
+ */
25
+ countBy<Entity extends object>(entityName: EntityName<Entity>, groupBy: EntityKey<Entity> | readonly EntityKey<Entity>[], options?: CountByOptions<Entity>): Promise<Dictionary<number>>;
22
26
  /**
23
27
  * @inheritDoc
24
28
  */
@@ -27,6 +27,37 @@ export class MongoEntityManager extends EntityManager {
27
27
  getCollection(entityOrCollectionName) {
28
28
  return this.getConnection().getCollection(entityOrCollectionName);
29
29
  }
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ async countBy(entityName, groupBy, options = {}) {
34
+ const em = this.getContext(false);
35
+ options = { ...options };
36
+ em.prepareOptions(options);
37
+ const meta = em.getMetadata().find(entityName);
38
+ const fields = Utils.asArray(groupBy);
39
+ if (options.having) {
40
+ throw new Error('The `having` option is not supported for MongoDB in `countBy`.');
41
+ }
42
+ await em.tryFlush(entityName, options);
43
+ const rawWhere = options.where;
44
+ const where = await em.processWhere(entityName, rawWhere ?? {}, options, 'read');
45
+ const renamedWhere = em.getDriver().renameFields(meta.class, where, true);
46
+ const fieldNames = fields.map(f => meta.properties[f]?.fieldNames?.[0] ?? f);
47
+ const groupId = fieldNames.length === 1 ? `$${fieldNames[0]}` : Object.fromEntries(fieldNames.map(f => [f, `$${f}`]));
48
+ const pipeline = [];
49
+ if (renamedWhere && Object.keys(renamedWhere).length > 0) {
50
+ pipeline.push({ $match: renamedWhere });
51
+ }
52
+ pipeline.push({ $group: { _id: groupId, count: { $sum: 1 } } });
53
+ const rows = await em.getDriver().aggregate(meta.class, pipeline, em.getTransactionContext());
54
+ const results = {};
55
+ for (const row of rows) {
56
+ const key = fieldNames.length === 1 ? String(row._id) : fieldNames.map(f => String(row._id[f])).join(Utils.PK_SEPARATOR);
57
+ results[key] = +row.count;
58
+ }
59
+ return results;
60
+ }
30
61
  /**
31
62
  * @inheritDoc
32
63
  */
@@ -2,17 +2,17 @@ import { type AnyEntity, type EntityClass, type EntitySchema, MikroORM, type Opt
2
2
  import { MongoDriver } from './MongoDriver.js';
3
3
  import type { MongoEntityManager } from './MongoEntityManager.js';
4
4
  /** Configuration options for the MongoDB driver. */
5
- export type MongoOptions<EM extends MongoEntityManager = MongoEntityManager, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> = Partial<Options<MongoDriver, EM, Entities>>;
5
+ export type MongoOptions<EM extends MongoEntityManager = MongoEntityManager, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> = Partial<Options<MongoDriver, EM, Entities>>;
6
6
  /** Creates a type-safe configuration object for the MongoDB driver. */
7
- export declare function defineMongoConfig<EM extends MongoEntityManager = MongoEntityManager, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: MongoOptions<EM, Entities>): MongoOptions<EM, Entities>;
7
+ export declare function defineMongoConfig<EM extends MongoEntityManager = MongoEntityManager, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: MongoOptions<EM, Entities>): MongoOptions<EM, Entities>;
8
8
  /**
9
9
  * @inheritDoc
10
10
  */
11
- export declare class MongoMikroORM<EM extends MongoEntityManager = MongoEntityManager, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends MikroORM<MongoDriver, EM, Entities> {
11
+ export declare class MongoMikroORM<EM extends MongoEntityManager = MongoEntityManager, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends MikroORM<MongoDriver, EM, Entities> {
12
12
  /**
13
13
  * @inheritDoc
14
14
  */
15
- static init<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
15
+ static init<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
16
16
  /**
17
17
  * @inheritDoc
18
18
  */
package/MongoPlatform.js CHANGED
@@ -76,6 +76,9 @@ export class MongoPlatform extends Platform {
76
76
  if (meta.inheritanceType === 'tpt') {
77
77
  throw MetadataError.tptNotSupportedByDriver(meta);
78
78
  }
79
+ if (meta.triggers?.length > 0) {
80
+ throw MetadataError.triggersNotSupportedByDriver(meta);
81
+ }
79
82
  const pk = meta.getPrimaryProps()[0];
80
83
  if (pk && pk.fieldNames?.[0] !== '_id') {
81
84
  throw MetadataError.invalidPrimaryKey(meta, pk, '_id');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/mongodb",
3
- "version": "7.1.0-dev.1",
3
+ "version": "7.1.0-dev.11",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "keywords": [
6
6
  "data-mapper",
@@ -53,7 +53,7 @@
53
53
  "@mikro-orm/core": "^7.0.11"
54
54
  },
55
55
  "peerDependencies": {
56
- "@mikro-orm/core": "7.1.0-dev.1"
56
+ "@mikro-orm/core": "7.1.0-dev.11"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"