Skip to content

Commit 47c5f78

Browse files
authored
Merge pull request #11370 from Uzlopak/types-expression
types: Add Expression Typings to Pipeline Stages
2 parents 96edf20 + e3dca30 commit 47c5f78

File tree

6 files changed

+3422
-115
lines changed

6 files changed

+3422
-115
lines changed

.eslintrc.json

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,70 @@
44
],
55
"ignorePatterns": [
66
"docs",
7+
"tools",
78
"dist",
8-
"test/files/*"
9+
"website.js",
10+
"test/files/*",
11+
"benchmarks"
912
],
10-
"overrides": [{
11-
"files": [
12-
"**/*.{ts,tsx}"
13-
],
14-
"extends": [
15-
"plugin:@typescript-eslint/eslint-recommended",
16-
"plugin:@typescript-eslint/recommended"
17-
],
18-
"plugins": [
19-
"@typescript-eslint"
20-
],
21-
"rules": {
22-
"@typescript-eslint/triple-slash-reference": "off",
23-
"spaced-comment": ["error", "always", {
24-
"markers": ["/"]
25-
}],
26-
"@typescript-eslint/no-explicit-any": "off",
27-
"@typescript-eslint/ban-types": "off",
28-
"@typescript-eslint/no-unused-vars": "off",
29-
"@typescript-eslint/explicit-module-boundary-types": "off",
30-
"@typescript-eslint/indent": ["error", 2, {
31-
"SwitchCase": 1
32-
}],
33-
"@typescript-eslint/prefer-optional-chain": "error",
34-
"@typescript-eslint/brace-style": "error",
35-
"@typescript-eslint/no-dupe-class-members": "error",
36-
"@typescript-eslint/no-redeclare": "error",
37-
"@typescript-eslint/type-annotation-spacing": "error",
38-
"@typescript-eslint/object-curly-spacing": ["error", "always"],
39-
"@typescript-eslint/semi": "error",
40-
"@typescript-eslint/space-before-function-paren": ["error", "never"],
41-
"@typescript-eslint/space-infix-ops": "off"
13+
"overrides": [
14+
{
15+
"files": [
16+
"**/*.{ts,tsx}"
17+
],
18+
"extends": [
19+
"plugin:@typescript-eslint/eslint-recommended",
20+
"plugin:@typescript-eslint/recommended"
21+
],
22+
"plugins": [
23+
"@typescript-eslint"
24+
],
25+
"rules": {
26+
"@typescript-eslint/triple-slash-reference": "off",
27+
"spaced-comment": [
28+
"error",
29+
"always",
30+
{
31+
"block": {
32+
"markers": [
33+
"!"
34+
],
35+
"balanced": true
36+
},
37+
"markers": [
38+
"/"
39+
]
40+
}
41+
],
42+
"@typescript-eslint/no-explicit-any": "off",
43+
"@typescript-eslint/ban-types": "off",
44+
"@typescript-eslint/no-unused-vars": "off",
45+
"@typescript-eslint/explicit-module-boundary-types": "off",
46+
"@typescript-eslint/indent": [
47+
"error",
48+
2,
49+
{
50+
"SwitchCase": 1
51+
}
52+
],
53+
"@typescript-eslint/prefer-optional-chain": "error",
54+
"@typescript-eslint/brace-style": "error",
55+
"@typescript-eslint/no-dupe-class-members": "error",
56+
"@typescript-eslint/no-redeclare": "error",
57+
"@typescript-eslint/type-annotation-spacing": "error",
58+
"@typescript-eslint/object-curly-spacing": [
59+
"error",
60+
"always"
61+
],
62+
"@typescript-eslint/semi": "error",
63+
"@typescript-eslint/space-before-function-paren": [
64+
"error",
65+
"never"
66+
],
67+
"@typescript-eslint/space-infix-ops": "off"
68+
}
4269
}
43-
}],
70+
],
4471
"plugins": [
4572
"mocha-no-only"
4673
],

test/types/PipelineStage.test.ts

Lines changed: 242 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,245 @@ const unwind1: PipelineStage = { $unwind: '$sizes' };
128128
const unwind2: PipelineStage = { $unwind: { path: '$sizes' } };
129129
const unwind3: PipelineStage = { $unwind: { path: '$sizes', includeArrayIndex: 'arrayIndex' } };
130130
const unwind4: PipelineStage = { $unwind: { path: '$sizes', preserveNullAndEmptyArrays: true } };
131-
const unwind5: PipelineStage = { $unwind: { path: '$sizes', preserveNullAndEmptyArrays: true } };
131+
const unwind5: PipelineStage = { $unwind: { path: '$sizes', preserveNullAndEmptyArrays: true } };
132+
133+
const redact1: PipelineStage = {
134+
$redact: {
135+
$cond: {
136+
if: { $gt: [{ $size: { $setIntersection: ['$tags', 'userAccess'] } }, 0] },
137+
then: '$$DESCEND',
138+
else: '$$PRUNE'
139+
}
140+
}
141+
};
142+
143+
const redact2: PipelineStage = {
144+
$redact: {
145+
$cond: {
146+
if: { $eq: ['$level', 5] },
147+
then: '$$PRUNE',
148+
else: '$$DESCEND'
149+
}
150+
}
151+
};
152+
const replaceRoot: PipelineStage = { $replaceRoot: { newRoot: { $mergeObjects: [{ dogs: 0, cats: 0, birds: 0, fish: 0 }, '$pets'] } } };
153+
154+
const project1: PipelineStage = { $project: { contact: 1, 'contact.address.country': 1 } };
155+
const project2: PipelineStage = { $project: { 'contact.address.country': 1, contact: 1 } };
156+
const project3: PipelineStage = { $project: { author: { first: 0 }, lastModified: 0 } };
157+
const project4: PipelineStage = {
158+
$project: {
159+
title: 1,
160+
'author.first': 1,
161+
'author.last': 1,
162+
'author.middle': {
163+
$cond: {
164+
if: { $eq: ['', '$author.middle'] },
165+
then: '$$REMOVE',
166+
else: '$author.middle'
167+
}
168+
}
169+
}
170+
};
171+
const project5: PipelineStage = { $project: { 'stop.title': 1 } };
172+
const project6: PipelineStage = { $project: { stop: { title: 1 } } };
173+
const project7: PipelineStage = {
174+
$project: {
175+
title: 1,
176+
isbn: {
177+
prefix: { $substr: ['$isbn', 0, 3] },
178+
group: { $substr: ['$isbn', 3, 2] },
179+
publisher: { $substr: ['$isbn', 5, 4] },
180+
title: { $substr: ['$isbn', 9, 3] },
181+
checkDigit: { $substr: ['$isbn', 12, 1] }
182+
},
183+
lastName: '$author.last',
184+
copiesSold: '$copies'
185+
}
186+
};
187+
const project8: PipelineStage = { $project: { myArray: ['$x', '$y'] } };
188+
const project9: PipelineStage = { $project: { x: '$name.0', _id: 0 } };
189+
const project10: PipelineStage = { $project: { stdDev: { $stdDevPop: '$scores.score' } } };
190+
const project11: PipelineStage = {
191+
$project:
192+
{
193+
item: 1,
194+
comparisonResult: { $strcasecmp: ['$quarter', '13q4'] }
195+
}
196+
};
197+
const project12: PipelineStage = {
198+
$project: {
199+
name: 1,
200+
length: { $strLenBytes: '$name' }
201+
}
202+
};
203+
const project13: PipelineStage = {
204+
$project: {
205+
name: 1,
206+
length: { $strLenCP: '$name' }
207+
}
208+
};
209+
210+
const project14: PipelineStage = {
211+
$project:
212+
{
213+
item: 1,
214+
yearSubstring: { $substr: ['$quarter', 0, 2] },
215+
quarterSubtring: { $substr: ['$quarter', 2, -1] }
216+
}
217+
};
218+
const project15: PipelineStage = { $project: { item: 1, result: { $not: [{ $gt: ['$qty', 250] }] } } };
219+
220+
const sort1: PipelineStage = { $sort: { count: -1 } };
221+
const sortByCount1: PipelineStage = { $sortByCount: '$tags' };
222+
const sortByCount2: PipelineStage = { $sortByCount: { $mergeObjects: ['$employee', '$business'] } };
223+
224+
const set1: PipelineStage = { $set: { 'specs.fuel_type': 'unleaded' } };
225+
const set2: PipelineStage = { $set: { cats: 20 } };
226+
const set3: PipelineStage = { $set: { _id: '$item', item: 'fruit' } };
227+
const set4: PipelineStage = { $set: { homework: { $concatArrays: ['$homework', [7]] } } };
228+
229+
const merge1: PipelineStage = { $merge: { into: 'newDailySales201905', on: 'salesDate' } };
230+
const merge2: PipelineStage = { $merge: { into: 'newrestaurants', on: ['date', 'postcode'], whenMatched: 'replace', whenNotMatched: 'insert' } };
231+
const merge3: PipelineStage = { $merge: { into: { db: 'reporting', coll: 'budgets' }, on: '_id', whenMatched: 'replace', whenNotMatched: 'insert' } };
232+
const merge4: PipelineStage = { $merge: { into: { db: 'reporting', coll: 'orgArchive' }, on: ['dept', 'fiscal_year'], whenMatched: 'fail' } };
233+
const merge5: PipelineStage = { $merge: { into: 'quarterlyreport', on: '_id', whenMatched: 'merge', whenNotMatched: 'insert' } };
234+
const merge6: PipelineStage = {
235+
$merge: {
236+
into: 'monthlytotals',
237+
on: '_id',
238+
whenMatched: [
239+
{
240+
$addFields: {
241+
thumbsup: { $add: ['$thumbsup', '$$new.thumbsup'] },
242+
thumbsdown: { $add: ['$thumbsdown', '$$new.thumbsdown'] }
243+
}
244+
}],
245+
whenNotMatched: 'insert'
246+
}
247+
};
248+
249+
const match1: PipelineStage = { $match: { $or: [{ score: { $gt: 70, $lt: 90 } }, { views: { $gte: 1000 } }] } };
250+
const match2: PipelineStage = { $match: { test: 'bla' } };
251+
const match3: PipelineStage = { $match: { test: { $or: [{ score: { $gt: 70, $lt: 90 } }, { views: { $gte: 1000 } }] } } };
252+
const match4: PipelineStage = { $match: { $and: [{ score: { $gt: 70, $lt: 90 } }, { views: { $gte: 1000 } }] } };
253+
const match5: PipelineStage = { $match: { test: { $and: [{ score: { $gt: 70, $lt: 90 } }, { views: { $gte: 1000 } }] } } };
254+
const addFields7: PipelineStage = { $addFields: { convertedQty: { $toLong: '$qty' } } };
255+
256+
const setWindowFields1: PipelineStage = {
257+
$setWindowFields: {
258+
partitionBy: '$state',
259+
sortBy: { orderDate: 1 },
260+
output: {
261+
stdDevPopQuantityForState: {
262+
$stdDevPop: '$quantity',
263+
window: {
264+
documents: ['unbounded', 'current']
265+
}
266+
}
267+
}
268+
}
269+
};
270+
271+
const setWindowFields2: PipelineStage = {
272+
$setWindowFields: {
273+
partitionBy: '$state',
274+
sortBy: { orderDate: 1 },
275+
output: {
276+
stdDevSampQuantityForState: {
277+
$stdDevSamp: '$quantity',
278+
window: {
279+
documents: ['unbounded', 'current']
280+
}
281+
}
282+
}
283+
}
284+
};
285+
286+
const setWindowFields3: PipelineStage = {
287+
$setWindowFields: {
288+
partitionBy: '$stock',
289+
sortBy: { date: 1 },
290+
output: {
291+
expMovingAvgForStock: {
292+
$expMovingAvg: { input: '$price', N: 2 }
293+
}
294+
}
295+
}
296+
};
297+
298+
const setWindowFields4: PipelineStage = {
299+
$setWindowFields: {
300+
partitionBy: '$stock',
301+
sortBy: { date: 1 },
302+
output: {
303+
expMovingAvgForStock: {
304+
$expMovingAvg: { input: '$price', alpha: 0.75 }
305+
}
306+
}
307+
}
308+
};
309+
310+
const group1: PipelineStage = { $group: { _id: null, ageStdDev: { $stdDevSamp: '$age' } } };
311+
const group2: PipelineStage = {
312+
$group: {
313+
_id: { x: '$x' },
314+
y: { $first: '$y' }
315+
}
316+
};
317+
const group3: PipelineStage = {
318+
$group: {
319+
_id: null,
320+
count: { $count: {} }
321+
}
322+
};
323+
const group4: PipelineStage = {
324+
$group:
325+
{
326+
_id: '$item',
327+
totalSaleAmount: { $sum: { $multiply: ['$price', '$quantity'] } }
328+
}
329+
};
330+
const group5: PipelineStage = {
331+
$group: {
332+
_id: null,
333+
totalSaleAmount: { $sum: { $multiply: ['$price', '$quantity'] } },
334+
averageQuantity: { $avg: '$quantity' },
335+
count: { $sum: 1 }
336+
}
337+
};
338+
const group6: PipelineStage = { $group: { _id: '$author', books: { $push: '$title' } } };
339+
340+
const stages1: PipelineStage[] = [
341+
// First Stage
342+
{
343+
$match: { date: { $gte: new Date('2014-01-01'), $lt: new Date('2015-01-01') } }
344+
},
345+
// Second Stage
346+
{
347+
$group: {
348+
_id: { $dateToString: { format: '%Y-%m-%d', date: '$date' } },
349+
totalSaleAmount: { $sum: { $multiply: ['$price', '$quantity'] } },
350+
averageQuantity: { $avg: '$quantity' },
351+
count: { $sum: 1 }
352+
}
353+
},
354+
// Third Stage
355+
{
356+
$sort: { totalSaleAmount: -1 }
357+
}
358+
];
359+
360+
const stages2: PipelineStage[] = [
361+
// First Stage
362+
{
363+
$group: { _id: '$author', books: { $push: '$$ROOT' } }
364+
},
365+
// Second Stage
366+
{
367+
$addFields:
368+
{
369+
totalCopies: { $sum: '$books.copies' }
370+
}
371+
}
372+
];

0 commit comments

Comments
 (0)