@classytic/mongokit 3.0.6 → 3.1.0
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/README.md +4 -2
- package/dist/actions/index.d.ts +2 -2
- package/dist/actions/index.js +40 -9
- package/dist/{index-CkwbNdpJ.d.ts → index-3Nkm_Brq.d.ts} +170 -3
- package/dist/index.d.ts +997 -8
- package/dist/index.js +1202 -197
- package/dist/{queryParser-Do3SgsyJ.d.ts → mongooseToJsonSchema-CUQma8QK.d.ts} +8 -111
- package/dist/pagination/PaginationEngine.d.ts +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/{types-DDDYo18H.d.ts → types-CrSoCuWu.d.ts} +11 -31
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +104 -417
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -320,10 +320,12 @@ repo.on('error:create', ({ context, error }) => {
|
|
|
320
320
|
### Query Parser
|
|
321
321
|
|
|
322
322
|
```javascript
|
|
323
|
-
import {
|
|
323
|
+
import { QueryParser } from '@classytic/mongokit';
|
|
324
|
+
|
|
325
|
+
const queryParser = new QueryParser();
|
|
324
326
|
|
|
325
327
|
app.get('/users', async (req, res) => {
|
|
326
|
-
const { filters, limit, page, sort } = queryParser.
|
|
328
|
+
const { filters, limit, page, sort } = queryParser.parse(req.query);
|
|
327
329
|
const result = await userRepo.getAll({ filters, limit, page, sort });
|
|
328
330
|
res.json(result);
|
|
329
331
|
});
|
package/dist/actions/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { b as aggregate, c as create, _ as deleteActions, r as read, u as update } from '../index-3Nkm_Brq.js';
|
|
2
2
|
import 'mongoose';
|
|
3
|
-
import '../types-
|
|
3
|
+
import '../types-CrSoCuWu.js';
|
package/dist/actions/index.js
CHANGED
|
@@ -403,20 +403,51 @@ async function countBy(Model, field, query = {}, options = {}) {
|
|
|
403
403
|
return aggregate(Model, pipeline, options);
|
|
404
404
|
}
|
|
405
405
|
async function lookup(Model, lookupOptions) {
|
|
406
|
-
const { from, localField, foreignField, as, pipeline = [], query = {}, options = {} } = lookupOptions;
|
|
406
|
+
const { from, localField, foreignField, as, pipeline = [], let: letVars, query = {}, options = {} } = lookupOptions;
|
|
407
407
|
const aggPipeline = [];
|
|
408
408
|
if (Object.keys(query).length > 0) {
|
|
409
409
|
aggPipeline.push({ $match: query });
|
|
410
410
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
411
|
+
const usePipelineForm = pipeline.length > 0 || letVars;
|
|
412
|
+
if (usePipelineForm) {
|
|
413
|
+
if (pipeline.length === 0 && localField && foreignField) {
|
|
414
|
+
const autoPipeline = [
|
|
415
|
+
{
|
|
416
|
+
$match: {
|
|
417
|
+
$expr: {
|
|
418
|
+
$eq: [`$${foreignField}`, `$$${localField}`]
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
];
|
|
423
|
+
aggPipeline.push({
|
|
424
|
+
$lookup: {
|
|
425
|
+
from,
|
|
426
|
+
let: { [localField]: `$${localField}`, ...letVars || {} },
|
|
427
|
+
pipeline: autoPipeline,
|
|
428
|
+
as
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
} else {
|
|
432
|
+
aggPipeline.push({
|
|
433
|
+
$lookup: {
|
|
434
|
+
from,
|
|
435
|
+
...letVars && { let: letVars },
|
|
436
|
+
pipeline,
|
|
437
|
+
as
|
|
438
|
+
}
|
|
439
|
+
});
|
|
418
440
|
}
|
|
419
|
-
}
|
|
441
|
+
} else {
|
|
442
|
+
aggPipeline.push({
|
|
443
|
+
$lookup: {
|
|
444
|
+
from,
|
|
445
|
+
localField,
|
|
446
|
+
foreignField,
|
|
447
|
+
as
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
420
451
|
return aggregate(Model, aggPipeline, options);
|
|
421
452
|
}
|
|
422
453
|
async function unwind(Model, field, options = {}) {
|
|
@@ -1,5 +1,166 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A as AnyDocument,
|
|
1
|
+
import { PipelineStage, ClientSession, Model } from 'mongoose';
|
|
2
|
+
import { A as AnyDocument, r as CreateOptions, k as ObjectId, q as OperationOptions, S as SelectSpec, e as PopulateSpec, f as SortSpec, l as UpdateOptions, t as UpdateWithValidationResult, s as UpdateManyResult, D as DeleteResult, Q as GroupResult, T as MinMaxResult } from './types-CrSoCuWu.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* LookupBuilder - MongoDB $lookup Utility
|
|
6
|
+
*
|
|
7
|
+
* Standalone builder for efficient custom field joins using MongoDB $lookup aggregation.
|
|
8
|
+
* Optimized for millions of records with proper index usage.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Join on custom fields (slugs, SKUs, codes, etc.)
|
|
12
|
+
* - Pipeline support for complex transformations
|
|
13
|
+
* - Index-aware query building
|
|
14
|
+
* - Single vs Array result handling
|
|
15
|
+
* - Nested lookups
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Simple lookup - join employees with departments by slug
|
|
20
|
+
* const lookup = new LookupBuilder('departments')
|
|
21
|
+
* .localField('departmentSlug')
|
|
22
|
+
* .foreignField('slug')
|
|
23
|
+
* .as('department')
|
|
24
|
+
* .single(); // Unwrap array to single object
|
|
25
|
+
*
|
|
26
|
+
* const pipeline = lookup.build();
|
|
27
|
+
* const results = await Employee.aggregate(pipeline);
|
|
28
|
+
*
|
|
29
|
+
* // Advanced lookup with pipeline
|
|
30
|
+
* const lookup = new LookupBuilder('products')
|
|
31
|
+
* .localField('productIds')
|
|
32
|
+
* .foreignField('sku')
|
|
33
|
+
* .pipeline([
|
|
34
|
+
* { $match: { status: 'active' } },
|
|
35
|
+
* { $project: { name: 1, price: 1 } }
|
|
36
|
+
* ])
|
|
37
|
+
* .as('products');
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
interface LookupOptions {
|
|
42
|
+
/** Collection to join with */
|
|
43
|
+
from: string;
|
|
44
|
+
/** Field from the input documents */
|
|
45
|
+
localField: string;
|
|
46
|
+
/** Field from the documents of the "from" collection */
|
|
47
|
+
foreignField: string;
|
|
48
|
+
/** Name of the new array field to add to the input documents */
|
|
49
|
+
as?: string;
|
|
50
|
+
/** Whether to unwrap array to single object */
|
|
51
|
+
single?: boolean;
|
|
52
|
+
/** Additional pipeline to run on the joined collection */
|
|
53
|
+
pipeline?: PipelineStage[];
|
|
54
|
+
/** Optional let variables for pipeline */
|
|
55
|
+
let?: Record<string, string>;
|
|
56
|
+
/** Query filter to apply before join (legacy, for aggregate.ts compatibility) */
|
|
57
|
+
query?: Record<string, unknown>;
|
|
58
|
+
/** Query options (legacy, for aggregate.ts compatibility) */
|
|
59
|
+
options?: {
|
|
60
|
+
session?: ClientSession;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Fluent builder for MongoDB $lookup aggregation stage
|
|
65
|
+
* Optimized for custom field joins at scale
|
|
66
|
+
*/
|
|
67
|
+
declare class LookupBuilder {
|
|
68
|
+
private options;
|
|
69
|
+
constructor(from?: string);
|
|
70
|
+
/**
|
|
71
|
+
* Set the collection to join with
|
|
72
|
+
*/
|
|
73
|
+
from(collection: string): this;
|
|
74
|
+
/**
|
|
75
|
+
* Set the local field (source collection)
|
|
76
|
+
* IMPORTANT: This field should be indexed for optimal performance
|
|
77
|
+
*/
|
|
78
|
+
localField(field: string): this;
|
|
79
|
+
/**
|
|
80
|
+
* Set the foreign field (target collection)
|
|
81
|
+
* IMPORTANT: This field should be indexed (preferably unique) for optimal performance
|
|
82
|
+
*/
|
|
83
|
+
foreignField(field: string): this;
|
|
84
|
+
/**
|
|
85
|
+
* Set the output field name
|
|
86
|
+
* Defaults to the collection name if not specified
|
|
87
|
+
*/
|
|
88
|
+
as(fieldName: string): this;
|
|
89
|
+
/**
|
|
90
|
+
* Mark this lookup as returning a single document
|
|
91
|
+
* Automatically unwraps the array result to a single object or null
|
|
92
|
+
*/
|
|
93
|
+
single(isSingle?: boolean): this;
|
|
94
|
+
/**
|
|
95
|
+
* Add a pipeline to filter/transform joined documents
|
|
96
|
+
* Useful for filtering, sorting, or limiting joined results
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* lookup.pipeline([
|
|
101
|
+
* { $match: { status: 'active' } },
|
|
102
|
+
* { $sort: { priority: -1 } },
|
|
103
|
+
* { $limit: 5 }
|
|
104
|
+
* ]);
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
pipeline(stages: PipelineStage[]): this;
|
|
108
|
+
/**
|
|
109
|
+
* Set let variables for use in pipeline
|
|
110
|
+
* Allows referencing local document fields in the pipeline
|
|
111
|
+
*/
|
|
112
|
+
let(variables: Record<string, string>): this;
|
|
113
|
+
/**
|
|
114
|
+
* Build the $lookup aggregation stage(s)
|
|
115
|
+
* Returns an array of pipeline stages including $lookup and optional $unwind
|
|
116
|
+
*
|
|
117
|
+
* IMPORTANT: MongoDB $lookup has two mutually exclusive forms:
|
|
118
|
+
* 1. Simple form: { from, localField, foreignField, as }
|
|
119
|
+
* 2. Pipeline form: { from, let, pipeline, as }
|
|
120
|
+
*
|
|
121
|
+
* When pipeline or let is specified, we use the pipeline form.
|
|
122
|
+
* Otherwise, we use the simpler localField/foreignField form.
|
|
123
|
+
*/
|
|
124
|
+
build(): PipelineStage[];
|
|
125
|
+
/**
|
|
126
|
+
* Build and return only the $lookup stage (without $unwind)
|
|
127
|
+
* Useful when you want to handle unwrapping yourself
|
|
128
|
+
*/
|
|
129
|
+
buildLookupOnly(): PipelineStage.Lookup;
|
|
130
|
+
/**
|
|
131
|
+
* Static helper: Create a simple lookup in one line
|
|
132
|
+
*/
|
|
133
|
+
static simple(from: string, localField: string, foreignField: string, options?: {
|
|
134
|
+
as?: string;
|
|
135
|
+
single?: boolean;
|
|
136
|
+
}): PipelineStage[];
|
|
137
|
+
/**
|
|
138
|
+
* Static helper: Create multiple lookups at once
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* const pipeline = LookupBuilder.multiple([
|
|
143
|
+
* { from: 'departments', localField: 'deptSlug', foreignField: 'slug', single: true },
|
|
144
|
+
* { from: 'managers', localField: 'managerId', foreignField: '_id', single: true }
|
|
145
|
+
* ]);
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
static multiple(lookups: LookupOptions[]): PipelineStage[];
|
|
149
|
+
/**
|
|
150
|
+
* Static helper: Create a nested lookup (lookup within lookup)
|
|
151
|
+
* Useful for multi-level joins like Order -> Product -> Category
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // Join orders with products, then products with categories
|
|
156
|
+
* const pipeline = LookupBuilder.nested([
|
|
157
|
+
* { from: 'products', localField: 'productSku', foreignField: 'sku', as: 'product', single: true },
|
|
158
|
+
* { from: 'categories', localField: 'product.categorySlug', foreignField: 'slug', as: 'product.category', single: true }
|
|
159
|
+
* ]);
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
static nested(lookups: LookupOptions[]): PipelineStage[];
|
|
163
|
+
}
|
|
3
164
|
|
|
4
165
|
/**
|
|
5
166
|
* Create Actions
|
|
@@ -269,6 +430,12 @@ declare function countBy(Model: Model<any>, field: string, query?: Record<string
|
|
|
269
430
|
}): Promise<GroupResult[]>;
|
|
270
431
|
/**
|
|
271
432
|
* Lookup (join) with another collection
|
|
433
|
+
*
|
|
434
|
+
* MongoDB $lookup has two mutually exclusive forms:
|
|
435
|
+
* 1. Simple form: { from, localField, foreignField, as }
|
|
436
|
+
* 2. Pipeline form: { from, let, pipeline, as }
|
|
437
|
+
*
|
|
438
|
+
* This function automatically selects the appropriate form based on parameters.
|
|
272
439
|
*/
|
|
273
440
|
declare function lookup<TDoc = AnyDocument>(Model: Model<TDoc>, lookupOptions: LookupOptions): Promise<TDoc[]>;
|
|
274
441
|
/**
|
|
@@ -334,4 +501,4 @@ declare namespace index {
|
|
|
334
501
|
export { aggregate$1 as aggregate, create$1 as create, _delete as deleteActions, index_read as read, update$1 as update };
|
|
335
502
|
}
|
|
336
503
|
|
|
337
|
-
export { _delete as _, aggregate$1 as
|
|
504
|
+
export { type LookupOptions as L, _delete as _, LookupBuilder as a, aggregate$1 as b, create$1 as c, index as i, read as r, update$1 as u };
|