@atscript/db-mongo 0.1.128 → 0.1.129
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/dist/agg.cjs +35 -15
- package/dist/agg.d.cts +6 -2
- package/dist/agg.d.mts +6 -2
- package/dist/agg.mjs +35 -15
- package/package.json +2 -2
package/dist/agg.cjs
CHANGED
|
@@ -60,17 +60,28 @@ function buildPrefix(query) {
|
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* The stages every grouped query shares: `$match(filter)` → `$group`
|
|
64
|
+
* (dimensions + accumulators) → `$project` (flatten `_id`, keep aliases) →
|
|
65
|
+
* `$match($having)`. The row pipeline appends sort/skip/limit, the count
|
|
66
|
+
* pipeline appends `$count`, so both see exactly the same group set.
|
|
64
67
|
*
|
|
65
|
-
*
|
|
68
|
+
* With `accumulators: false` only the `$group._id` dimensions are emitted
|
|
69
|
+
* (no accumulators, no `$project`, no `$having`) — the cheapest shape for a
|
|
70
|
+
* plain group count, where no alias has to be resolvable.
|
|
66
71
|
*/
|
|
67
|
-
function
|
|
72
|
+
function buildGroupedStages(query, { accumulators }) {
|
|
68
73
|
const { pipeline, groupId, groupKeys, controls } = buildPrefix(query);
|
|
69
74
|
const groupStage = { _id: groupId };
|
|
75
|
+
if (!accumulators) {
|
|
76
|
+
pipeline.push({ $group: groupStage });
|
|
77
|
+
return {
|
|
78
|
+
pipeline,
|
|
79
|
+
controls
|
|
80
|
+
};
|
|
81
|
+
}
|
|
70
82
|
const project = { _id: 0 };
|
|
71
|
-
const aggregates = controls.$select?.aggregates;
|
|
72
83
|
for (const [field, idKey] of groupKeys) project[field] = `$_id.${idKey}`;
|
|
73
|
-
|
|
84
|
+
for (const expr of controls.$select?.aggregates ?? []) {
|
|
74
85
|
const alias = (0, _atscript_db_agg.resolveAlias)(expr);
|
|
75
86
|
groupStage[alias] = toAccumulator(expr);
|
|
76
87
|
project[alias] = 1;
|
|
@@ -78,25 +89,34 @@ function buildAggregatePipeline(query) {
|
|
|
78
89
|
pipeline.push({ $group: groupStage });
|
|
79
90
|
pipeline.push({ $project: project });
|
|
80
91
|
if (controls.$having) pipeline.push({ $match: require_mongo_filter.buildMongoFilter(controls.$having) });
|
|
92
|
+
return {
|
|
93
|
+
pipeline,
|
|
94
|
+
controls
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Builds a full MongoDB aggregation pipeline for GROUP BY queries.
|
|
99
|
+
*
|
|
100
|
+
* Pipeline: $match → $group → $project → $match(having) → $sort → $skip → $limit
|
|
101
|
+
*/
|
|
102
|
+
function buildAggregatePipeline(query) {
|
|
103
|
+
const { pipeline, controls } = buildGroupedStages(query, { accumulators: true });
|
|
81
104
|
if (controls.$sort) pipeline.push({ $sort: controls.$sort });
|
|
82
105
|
if (controls.$skip) pipeline.push({ $skip: controls.$skip });
|
|
83
106
|
if (controls.$limit) pipeline.push({ $limit: controls.$limit });
|
|
84
107
|
return pipeline;
|
|
85
108
|
}
|
|
86
109
|
/**
|
|
87
|
-
* Builds a count-only pipeline:
|
|
110
|
+
* Builds a count-only pipeline: the number of groups that survive `$having`
|
|
111
|
+
* (all groups when there is none). With `$having` it runs the same grouped
|
|
112
|
+
* stages as the row pipeline — the accumulators must run so an alias
|
|
113
|
+
* `$having` has a value to match; without it only the `$group._id`
|
|
114
|
+
* dimensions are needed.
|
|
88
115
|
*
|
|
89
|
-
* Pipeline: $match → $group
|
|
116
|
+
* Pipeline: $match → $group → [$project → $match(having)] → $count
|
|
90
117
|
*/
|
|
91
118
|
function buildCountPipeline(query) {
|
|
92
|
-
const { pipeline
|
|
93
|
-
pipeline.push({ $group: { _id: groupId } });
|
|
94
|
-
if (controls.$having) {
|
|
95
|
-
const project = { _id: 0 };
|
|
96
|
-
for (const [field, idKey] of groupKeys) project[field] = `$_id.${idKey}`;
|
|
97
|
-
pipeline.push({ $project: project });
|
|
98
|
-
pipeline.push({ $match: require_mongo_filter.buildMongoFilter(controls.$having) });
|
|
99
|
-
}
|
|
119
|
+
const { pipeline } = buildGroupedStages(query, { accumulators: Boolean(query.controls?.$having) });
|
|
100
120
|
pipeline.push({ $count: "count" });
|
|
101
121
|
return pipeline;
|
|
102
122
|
}
|
package/dist/agg.d.cts
CHANGED
|
@@ -9,9 +9,13 @@ import { Document } from "mongodb";
|
|
|
9
9
|
*/
|
|
10
10
|
declare function buildAggregatePipeline(query: DbQuery): Document[];
|
|
11
11
|
/**
|
|
12
|
-
* Builds a count-only pipeline:
|
|
12
|
+
* Builds a count-only pipeline: the number of groups that survive `$having`
|
|
13
|
+
* (all groups when there is none). With `$having` it runs the same grouped
|
|
14
|
+
* stages as the row pipeline — the accumulators must run so an alias
|
|
15
|
+
* `$having` has a value to match; without it only the `$group._id`
|
|
16
|
+
* dimensions are needed.
|
|
13
17
|
*
|
|
14
|
-
* Pipeline: $match → $group
|
|
18
|
+
* Pipeline: $match → $group → [$project → $match(having)] → $count
|
|
15
19
|
*/
|
|
16
20
|
declare function buildCountPipeline(query: DbQuery): Document[];
|
|
17
21
|
//#endregion
|
package/dist/agg.d.mts
CHANGED
|
@@ -9,9 +9,13 @@ import { Document } from "mongodb";
|
|
|
9
9
|
*/
|
|
10
10
|
declare function buildAggregatePipeline(query: DbQuery): Document[];
|
|
11
11
|
/**
|
|
12
|
-
* Builds a count-only pipeline:
|
|
12
|
+
* Builds a count-only pipeline: the number of groups that survive `$having`
|
|
13
|
+
* (all groups when there is none). With `$having` it runs the same grouped
|
|
14
|
+
* stages as the row pipeline — the accumulators must run so an alias
|
|
15
|
+
* `$having` has a value to match; without it only the `$group._id`
|
|
16
|
+
* dimensions are needed.
|
|
13
17
|
*
|
|
14
|
-
* Pipeline: $match → $group
|
|
18
|
+
* Pipeline: $match → $group → [$project → $match(having)] → $count
|
|
15
19
|
*/
|
|
16
20
|
declare function buildCountPipeline(query: DbQuery): Document[];
|
|
17
21
|
//#endregion
|
package/dist/agg.mjs
CHANGED
|
@@ -59,17 +59,28 @@ function buildPrefix(query) {
|
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
62
|
+
* The stages every grouped query shares: `$match(filter)` → `$group`
|
|
63
|
+
* (dimensions + accumulators) → `$project` (flatten `_id`, keep aliases) →
|
|
64
|
+
* `$match($having)`. The row pipeline appends sort/skip/limit, the count
|
|
65
|
+
* pipeline appends `$count`, so both see exactly the same group set.
|
|
63
66
|
*
|
|
64
|
-
*
|
|
67
|
+
* With `accumulators: false` only the `$group._id` dimensions are emitted
|
|
68
|
+
* (no accumulators, no `$project`, no `$having`) — the cheapest shape for a
|
|
69
|
+
* plain group count, where no alias has to be resolvable.
|
|
65
70
|
*/
|
|
66
|
-
function
|
|
71
|
+
function buildGroupedStages(query, { accumulators }) {
|
|
67
72
|
const { pipeline, groupId, groupKeys, controls } = buildPrefix(query);
|
|
68
73
|
const groupStage = { _id: groupId };
|
|
74
|
+
if (!accumulators) {
|
|
75
|
+
pipeline.push({ $group: groupStage });
|
|
76
|
+
return {
|
|
77
|
+
pipeline,
|
|
78
|
+
controls
|
|
79
|
+
};
|
|
80
|
+
}
|
|
69
81
|
const project = { _id: 0 };
|
|
70
|
-
const aggregates = controls.$select?.aggregates;
|
|
71
82
|
for (const [field, idKey] of groupKeys) project[field] = `$_id.${idKey}`;
|
|
72
|
-
|
|
83
|
+
for (const expr of controls.$select?.aggregates ?? []) {
|
|
73
84
|
const alias = resolveAlias(expr);
|
|
74
85
|
groupStage[alias] = toAccumulator(expr);
|
|
75
86
|
project[alias] = 1;
|
|
@@ -77,25 +88,34 @@ function buildAggregatePipeline(query) {
|
|
|
77
88
|
pipeline.push({ $group: groupStage });
|
|
78
89
|
pipeline.push({ $project: project });
|
|
79
90
|
if (controls.$having) pipeline.push({ $match: buildMongoFilter(controls.$having) });
|
|
91
|
+
return {
|
|
92
|
+
pipeline,
|
|
93
|
+
controls
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Builds a full MongoDB aggregation pipeline for GROUP BY queries.
|
|
98
|
+
*
|
|
99
|
+
* Pipeline: $match → $group → $project → $match(having) → $sort → $skip → $limit
|
|
100
|
+
*/
|
|
101
|
+
function buildAggregatePipeline(query) {
|
|
102
|
+
const { pipeline, controls } = buildGroupedStages(query, { accumulators: true });
|
|
80
103
|
if (controls.$sort) pipeline.push({ $sort: controls.$sort });
|
|
81
104
|
if (controls.$skip) pipeline.push({ $skip: controls.$skip });
|
|
82
105
|
if (controls.$limit) pipeline.push({ $limit: controls.$limit });
|
|
83
106
|
return pipeline;
|
|
84
107
|
}
|
|
85
108
|
/**
|
|
86
|
-
* Builds a count-only pipeline:
|
|
109
|
+
* Builds a count-only pipeline: the number of groups that survive `$having`
|
|
110
|
+
* (all groups when there is none). With `$having` it runs the same grouped
|
|
111
|
+
* stages as the row pipeline — the accumulators must run so an alias
|
|
112
|
+
* `$having` has a value to match; without it only the `$group._id`
|
|
113
|
+
* dimensions are needed.
|
|
87
114
|
*
|
|
88
|
-
* Pipeline: $match → $group
|
|
115
|
+
* Pipeline: $match → $group → [$project → $match(having)] → $count
|
|
89
116
|
*/
|
|
90
117
|
function buildCountPipeline(query) {
|
|
91
|
-
const { pipeline
|
|
92
|
-
pipeline.push({ $group: { _id: groupId } });
|
|
93
|
-
if (controls.$having) {
|
|
94
|
-
const project = { _id: 0 };
|
|
95
|
-
for (const [field, idKey] of groupKeys) project[field] = `$_id.${idKey}`;
|
|
96
|
-
pipeline.push({ $project: project });
|
|
97
|
-
pipeline.push({ $match: buildMongoFilter(controls.$having) });
|
|
98
|
-
}
|
|
118
|
+
const { pipeline } = buildGroupedStages(query, { accumulators: Boolean(query.controls?.$having) });
|
|
99
119
|
pipeline.push({ $count: "count" });
|
|
100
120
|
return pipeline;
|
|
101
121
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-mongo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.129",
|
|
4
4
|
"description": "Mongodb plugin for atscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@atscript/core": "^0.1.92",
|
|
57
57
|
"@atscript/typescript": "^0.1.92",
|
|
58
58
|
"mongodb": "^6.17.0",
|
|
59
|
-
"@atscript/db": "^0.1.
|
|
59
|
+
"@atscript/db": "^0.1.129"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"postinstall": "asc -f dts",
|