@tmlmobilidade/export-data 20260121.2317.48 → 20260123.1211.24

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/index.js CHANGED
@@ -9,11 +9,8 @@ import { promptFilterByStopIds } from './prompts/filter-stop-ids.js';
9
9
  import { promptFilterTypes } from './prompts/filter-types.js';
10
10
  import { promptFilterByVehicleIds } from './prompts/filter-vehicle-ids.js';
11
11
  import { promptHashedShapeIds } from './prompts/hashedshape-ids.js';
12
- import { exportValidationsByLine } from './tasks/apex-validations/validations-by-line.js';
13
- import { exportValidationsByPattern } from './tasks/apex-validations/validations-by-pattern.js';
14
- import { exportValidationsByStopByPattern } from './tasks/apex-validations/validations-by-stop-by-pattern.js';
15
- import { exportValidationsByStopByTrip } from './tasks/apex-validations/validations-by-stop-by-trip.js';
16
- import { exportValidationsByStop } from './tasks/apex-validations/validations-by-stop.js';
12
+ import { promptValidationGroupFields } from './prompts/validation-group-fields.js';
13
+ import { exportValidationsAggregated } from './tasks/apex-validations/validations-aggregated.js';
17
14
  import { exportValidationsRaw } from './tasks/apex-validations/validations-raw.js';
18
15
  import { exportHashedShapesGeoJSON } from './tasks/hashed-shapes/hashed-shapes-geojson.js';
19
16
  import { exportRidesRaw } from './tasks/rides/rides-raw.js';
@@ -53,6 +50,12 @@ import { ASCII_CM_SHORT } from '@tmlmobilidade/consts';
53
50
  hashedShapeIds = await promptHashedShapeIds();
54
51
  }
55
52
  //
53
+ // For validations-aggregated export, prompt for group fields
54
+ let validationGroupFields = [];
55
+ if (exportTypes.includes('validations-aggregated')) {
56
+ validationGroupFields = await promptValidationGroupFields();
57
+ }
58
+ //
56
59
  // Skip filters and dates if all selected export types don't require them
57
60
  if (!shouldSkipFilters) {
58
61
  const filterTypes = await promptFilterTypes();
@@ -79,29 +82,9 @@ import { ASCII_CM_SHORT } from '@tmlmobilidade/consts';
79
82
  title: exportTypeLabels['validations-raw'],
80
83
  },
81
84
  {
82
- enabled: exportTypes.includes('validations-by-stop-by-trip'),
83
- task: async (message) => await exportValidationsByStopByTrip({ context, message }),
84
- title: exportTypeLabels['validations-by-stop-by-trip'],
85
- },
86
- {
87
- enabled: exportTypes.includes('validations-by-stop-by-pattern'),
88
- task: async (message) => await exportValidationsByStopByPattern({ context, message }),
89
- title: exportTypeLabels['validations-by-stop-by-pattern'],
90
- },
91
- {
92
- enabled: exportTypes.includes('validations-by-stop'),
93
- task: async (message) => await exportValidationsByStop({ context, message }),
94
- title: exportTypeLabels['validations-by-stop'],
95
- },
96
- {
97
- enabled: exportTypes.includes('validations-by-pattern'),
98
- task: async (message) => await exportValidationsByPattern({ context, message }),
99
- title: exportTypeLabels['validations-by-pattern'],
100
- },
101
- {
102
- enabled: exportTypes.includes('validations-by-line'),
103
- task: async (message) => await exportValidationsByLine({ context, message }),
104
- title: exportTypeLabels['validations-by-line'],
85
+ enabled: exportTypes.includes('validations-aggregated'),
86
+ task: async (message) => await exportValidationsAggregated({ context, groupFields: validationGroupFields, message }),
87
+ title: exportTypeLabels['validations-aggregated'],
105
88
  },
106
89
  {
107
90
  enabled: exportTypes.includes('rides-raw'),
@@ -9,11 +9,7 @@ export async function promptExportTypes() {
9
9
  options: {
10
10
  '1. Validações APEX': [
11
11
  { label: exportTypeLabels['validations-raw'], value: 'validations-raw' },
12
- { label: exportTypeLabels['validations-by-stop-by-trip'], value: 'validations-by-stop-by-trip' },
13
- { label: exportTypeLabels['validations-by-stop-by-pattern'], value: 'validations-by-stop-by-pattern' },
14
- { label: exportTypeLabels['validations-by-stop'], value: 'validations-by-stop' },
15
- { label: exportTypeLabels['validations-by-pattern'], value: 'validations-by-pattern' },
16
- { label: exportTypeLabels['validations-by-line'], value: 'validations-by-line' },
12
+ { label: exportTypeLabels['validations-aggregated'], value: 'validations-aggregated' },
17
13
  ],
18
14
  '2. Rides': [
19
15
  { label: exportTypeLabels['rides-raw'], value: 'rides-raw' },
@@ -0,0 +1,2 @@
1
+ import { type ValidationGroupField } from '../tasks/apex-validations/validations-aggregated.js';
2
+ export declare function promptValidationGroupFields(): Promise<ValidationGroupField[]>;
@@ -0,0 +1,22 @@
1
+ /* * */
2
+ import { validationGroupFieldLabels, validationGroupFields } from '../tasks/apex-validations/validations-aggregated.js';
3
+ import { cancel, isCancel, multiselect } from '@clack/prompts';
4
+ /* * */
5
+ export async function promptValidationGroupFields() {
6
+ //
7
+ const values = await multiselect({
8
+ message: 'Escolhe os campos para agrupar as validações (a data é sempre incluída):',
9
+ options: validationGroupFields.map(field => ({
10
+ label: validationGroupFieldLabels[field],
11
+ value: field,
12
+ })),
13
+ required: true,
14
+ });
15
+ if (isCancel(values)) {
16
+ cancel('Operação cancelada pelo utilizador.');
17
+ process.exit(0);
18
+ }
19
+ if (!values)
20
+ return [];
21
+ return values;
22
+ }
@@ -0,0 +1,18 @@
1
+ import { type TaskProps } from '../../types.js';
2
+ /**
3
+ * Available fields for grouping validations.
4
+ * 'date' is always included by default.
5
+ */
6
+ export declare const validationGroupFields: readonly ["line_id", "pattern_id", "product_id", "trip_id", "stop_id", "agency_id", "vehicle_id"];
7
+ export type ValidationGroupField = typeof validationGroupFields[number];
8
+ export declare const validationGroupFieldLabels: Record<ValidationGroupField, string>;
9
+ interface ValidationAggregatedTaskProps extends TaskProps {
10
+ groupFields: ValidationGroupField[];
11
+ }
12
+ /**
13
+ * Export Validations aggregated by user-selected fields.
14
+ * Always groups by date, plus any additional fields selected by the user.
15
+ * The 'validations' count is always included.
16
+ */
17
+ export declare function exportValidationsAggregated({ context, groupFields, message }: ValidationAggregatedTaskProps): Promise<void>;
18
+ export {};
@@ -4,13 +4,30 @@ import { simplifiedApexValidations } from '@tmlmobilidade/interfaces';
4
4
  import { CsvWriter } from '@tmlmobilidade/writers';
5
5
  import fs from 'node:fs';
6
6
  /* * */
7
- const TASK_ID = 'validations-by-stop-by-pattern';
8
7
  /**
9
- * Export Validations By Stop By Pattern data applying the given filters.
8
+ * Available fields for grouping validations.
9
+ * 'date' is always included by default.
10
10
  */
11
- export async function exportValidationsByStopByPattern({ context, message }) {
11
+ export const validationGroupFields = ['line_id', 'pattern_id', 'product_id', 'trip_id', 'stop_id', 'agency_id', 'vehicle_id'];
12
+ export const validationGroupFieldLabels = {
13
+ agency_id: 'Operador (agency_id)',
14
+ line_id: 'Linha (line_id)',
15
+ pattern_id: 'Pattern (pattern_id)',
16
+ product_id: 'Tipo de passe (product_id)',
17
+ stop_id: 'Paragem (stop_id)',
18
+ trip_id: 'Viagem (trip_id)',
19
+ vehicle_id: 'Veículo (vehicle_id)',
20
+ };
21
+ /* * */
22
+ /**
23
+ * Export Validations aggregated by user-selected fields.
24
+ * Always groups by date, plus any additional fields selected by the user.
25
+ * The 'validations' count is always included.
26
+ */
27
+ export async function exportValidationsAggregated({ context, groupFields, message }) {
12
28
  //
13
- message('A iniciar a exportação de Validações APEX por Paragem e por Pattern...');
29
+ const fieldsList = ['date', ...groupFields].join(', ');
30
+ message(`A iniciar a exportação de Validações APEX agrupadas por: ${fieldsList}...`);
14
31
  //
15
32
  // Prepare the filter params
16
33
  const filterQuery = {
@@ -51,7 +68,9 @@ export async function exportValidationsByStopByPattern({ context, message }) {
51
68
  message(`A preparar a pasta para guardar os resultados...`);
52
69
  if (!fs.existsSync(context.output))
53
70
  fs.mkdirSync(context.output, { recursive: true });
54
- const csvWriter = new CsvWriter('output', `${context.output}/${TASK_ID}-${context.dates.start}-${context.dates.end}.csv`, { batch_size: 100000, logs: false });
71
+ // Build filename based on selected fields
72
+ const fieldsSlug = groupFields.length > 0 ? `by-${groupFields.join('-')}` : 'by-date';
73
+ const csvWriter = new CsvWriter('output', `${context.output}/validations-${fieldsSlug}-${context.dates.start}-${context.dates.end}.csv`, { batch_size: 100000, logs: false });
55
74
  //
56
75
  // Export the data
57
76
  let counter = 0;
@@ -64,25 +83,42 @@ export async function exportValidationsByStopByPattern({ context, message }) {
64
83
  const operationalDate = Dates
65
84
  .fromUnixTimestamp(document.created_at)
66
85
  .operational_date;
67
- const resultKey = `${operationalDate}:${document.stop_id}:${document.pattern_id}`;
86
+ // Build the key from date + all selected group fields
87
+ const keyParts = [operationalDate, ...groupFields.map(field => String(document[field]))];
88
+ const resultKey = keyParts.join(':');
68
89
  //
69
90
  // Update the result with the current document
70
91
  if (!result[resultKey]) {
71
- result[resultKey] = {
92
+ // Initialize the result object with date first, then selected fields in order
93
+ const resultObj = {
72
94
  date: operationalDate,
73
- pattern_id: document.pattern_id,
74
- stop_id: document.stop_id,
75
- validations: 0,
76
95
  };
96
+ // Add each selected group field
97
+ for (const field of groupFields) {
98
+ resultObj[field] = document[field];
99
+ }
100
+ // Always add validations count at the end
101
+ resultObj.validations = 0;
102
+ result[resultKey] = resultObj;
77
103
  }
78
- result[resultKey].validations += 1;
104
+ result[resultKey].validations = result[resultKey].validations + 1;
79
105
  if (counter % 1000 === 0)
80
106
  message(`Processados ${counter} documentos até agora...`);
81
107
  counter++;
82
108
  //
83
109
  }
84
110
  message(`A escrever os resultados no ficheiro CSV...`);
85
- await csvWriter.write(Object.values(result));
111
+ // Write results in batches to avoid stack overflow with large datasets
112
+ const WRITE_BATCH_SIZE = 10000;
113
+ const resultKeys = Object.keys(result);
114
+ const totalResults = resultKeys.length;
115
+ for (let i = 0; i < totalResults; i += WRITE_BATCH_SIZE) {
116
+ const batch = resultKeys.slice(i, i + WRITE_BATCH_SIZE).map(key => result[key]);
117
+ await csvWriter.write(batch);
118
+ if (i % 50000 === 0 && i > 0) {
119
+ message(`Escritos ${i} de ${totalResults} resultados...`);
120
+ }
121
+ }
86
122
  await csvWriter.flush();
87
123
  //
88
124
  }
package/dist/types.d.ts CHANGED
@@ -3,11 +3,7 @@ export declare const exportTypeLabels: {
3
3
  readonly 'hashed-shapes-geojson': "4.0. HashedShapes para GeoJSON";
4
4
  readonly 'rides-raw': "2.0. Rides em bruto (SLAs)";
5
5
  readonly 'sams-raw': "5.0. SAMs em bruto (Sequencialidade)";
6
- readonly 'validations-by-line': "1.5. Validações por Line ID";
7
- readonly 'validations-by-pattern': "1.4. Validações por Pattern ID";
8
- readonly 'validations-by-stop': "1.3. Validações por Stop ID";
9
- readonly 'validations-by-stop-by-pattern': "1.2. Validações por Stop ID, por Pattern ID";
10
- readonly 'validations-by-stop-by-trip': "1.1. Validações por Stop ID, por Trip ID";
6
+ readonly 'validations-aggregated': "1.1. Validações agregadas (escolher campos)";
11
7
  readonly 'validations-raw': "1.0. Validações em bruto";
12
8
  readonly 'vehicle-events-raw': "3.0. Vehicle Events em bruto";
13
9
  };
package/dist/types.js CHANGED
@@ -4,11 +4,7 @@ export const exportTypeLabels = {
4
4
  'hashed-shapes-geojson': '4.0. HashedShapes para GeoJSON',
5
5
  'rides-raw': '2.0. Rides em bruto (SLAs)',
6
6
  'sams-raw': '5.0. SAMs em bruto (Sequencialidade)',
7
- 'validations-by-line': '1.5. Validações por Line ID',
8
- 'validations-by-pattern': '1.4. Validações por Pattern ID',
9
- 'validations-by-stop': '1.3. Validações por Stop ID',
10
- 'validations-by-stop-by-pattern': '1.2. Validações por Stop ID, por Pattern ID',
11
- 'validations-by-stop-by-trip': '1.1. Validações por Stop ID, por Trip ID',
7
+ 'validations-aggregated': '1.1. Validações agregadas (escolher campos)',
12
8
  'validations-raw': '1.0. Validações em bruto',
13
9
  'vehicle-events-raw': '3.0. Vehicle Events em bruto',
14
10
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tmlmobilidade/export-data",
3
3
  "description": "CLI tool to export data from GO.",
4
- "version": "20260121.2317.48",
4
+ "version": "20260123.1211.24",
5
5
  "author": {
6
6
  "email": "iso@tmlmobilidade.pt",
7
7
  "name": "TML-ISO"
@@ -1,2 +0,0 @@
1
- import { type TaskProps } from '../../types.js';
2
- export declare function exportValidationsByLine({ context, message }: TaskProps): Promise<void>;
@@ -1,85 +0,0 @@
1
- /* * */
2
- import { Dates } from '@tmlmobilidade/dates';
3
- import { simplifiedApexValidations } from '@tmlmobilidade/interfaces';
4
- import { CsvWriter } from '@tmlmobilidade/writers';
5
- import fs from 'node:fs';
6
- /* * */
7
- const TASK_ID = 'validations-by-line';
8
- /* * */
9
- export async function exportValidationsByLine({ context, message }) {
10
- //
11
- message('A iniciar a exportação de Validações APEX por Linha...');
12
- //
13
- // Prepare the filter params
14
- const filterQuery = {
15
- is_passenger: true,
16
- };
17
- filterQuery.created_at = {
18
- $gte: Dates
19
- .fromOperationalDate(context.dates.start, 'Europe/Lisbon')
20
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
21
- .unix_timestamp,
22
- $lt: Dates
23
- .fromOperationalDate(context.dates.end, 'Europe/Lisbon')
24
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
25
- .unix_timestamp,
26
- };
27
- if (context.filters.agency_ids.length) {
28
- filterQuery.agency_id = { $in: context.filters.agency_ids };
29
- }
30
- if (context.filters.line_ids.length) {
31
- filterQuery.line_id = { $in: context.filters.line_ids };
32
- }
33
- if (context.filters.pattern_ids.length) {
34
- filterQuery.pattern_id = { $in: context.filters.pattern_ids };
35
- }
36
- if (context.filters.stop_ids.length) {
37
- filterQuery.stop_id = { $in: context.filters.stop_ids };
38
- }
39
- if (context.filters.vehicle_ids.length) {
40
- filterQuery.vehicle_id = { $in: context.filters.vehicle_ids };
41
- }
42
- //
43
- // Setup a database stream to export data
44
- message(`A iniciar ligação à base de dados...`);
45
- const simplifiedApexValidationsCollection = await simplifiedApexValidations.getCollection();
46
- const stream = simplifiedApexValidationsCollection.find(filterQuery).stream();
47
- //
48
- // Prepare the output directory and CSV writer
49
- message(`A preparar a pasta para guardar os resultados...`);
50
- if (!fs.existsSync(context.output))
51
- fs.mkdirSync(context.output, { recursive: true });
52
- const csvWriter = new CsvWriter('output', `${context.output}/${TASK_ID}-${context.dates.start}-${context.dates.end}.csv`, { batch_size: 100000, logs: false });
53
- //
54
- // Export the data
55
- let counter = 0;
56
- message(`A aguardar o resultado da pesquisa...`);
57
- const result = {};
58
- for await (const doc of stream) {
59
- const document = doc;
60
- //
61
- // Prepare the result key
62
- const operationalDate = Dates
63
- .fromUnixTimestamp(document.created_at)
64
- .operational_date;
65
- const resultKey = `${operationalDate}:${document.line_id}`;
66
- //
67
- // Update the result with the current document
68
- if (!result[resultKey]) {
69
- result[resultKey] = {
70
- date: operationalDate,
71
- line_id: document.line_id,
72
- validations: 0,
73
- };
74
- }
75
- result[resultKey].validations += 1;
76
- if (counter % 1000 === 0)
77
- message(`Processados ${counter} documentos até agora...`);
78
- counter++;
79
- //
80
- }
81
- message(`A escrever os resultados no ficheiro CSV...`);
82
- await csvWriter.write(Object.values(result));
83
- await csvWriter.flush();
84
- //
85
- }
@@ -1,5 +0,0 @@
1
- import { type TaskProps } from '../../types.js';
2
- /**
3
- * Export Validations By Pattern data applying the given filters.
4
- */
5
- export declare function exportValidationsByPattern({ context, message }: TaskProps): Promise<void>;
@@ -1,87 +0,0 @@
1
- /* * */
2
- import { Dates } from '@tmlmobilidade/dates';
3
- import { simplifiedApexValidations } from '@tmlmobilidade/interfaces';
4
- import { CsvWriter } from '@tmlmobilidade/writers';
5
- import fs from 'node:fs';
6
- /* * */
7
- const TASK_ID = 'validations-by-pattern';
8
- /**
9
- * Export Validations By Pattern data applying the given filters.
10
- */
11
- export async function exportValidationsByPattern({ context, message }) {
12
- //
13
- message('A iniciar a exportação de Validações APEX por Pattern...');
14
- //
15
- // Prepare the filter params
16
- const filterQuery = {
17
- is_passenger: true,
18
- };
19
- filterQuery.created_at = {
20
- $gte: Dates
21
- .fromOperationalDate(context.dates.start, 'Europe/Lisbon')
22
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
23
- .unix_timestamp,
24
- $lt: Dates
25
- .fromOperationalDate(context.dates.end, 'Europe/Lisbon')
26
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
27
- .unix_timestamp,
28
- };
29
- if (context.filters.agency_ids.length) {
30
- filterQuery.agency_id = { $in: context.filters.agency_ids };
31
- }
32
- if (context.filters.line_ids.length) {
33
- filterQuery.line_id = { $in: context.filters.line_ids };
34
- }
35
- if (context.filters.pattern_ids.length) {
36
- filterQuery.pattern_id = { $in: context.filters.pattern_ids };
37
- }
38
- if (context.filters.stop_ids.length) {
39
- filterQuery.stop_id = { $in: context.filters.stop_ids };
40
- }
41
- if (context.filters.vehicle_ids.length) {
42
- filterQuery.vehicle_id = { $in: context.filters.vehicle_ids };
43
- }
44
- //
45
- // Setup a database stream to export data
46
- message(`A iniciar ligação à base de dados...`);
47
- const simplifiedApexValidationsCollection = await simplifiedApexValidations.getCollection();
48
- const stream = simplifiedApexValidationsCollection.find(filterQuery).stream();
49
- //
50
- // Prepare the output directory and CSV writer
51
- message(`A preparar a pasta para guardar os resultados...`);
52
- if (!fs.existsSync(context.output))
53
- fs.mkdirSync(context.output, { recursive: true });
54
- const csvWriter = new CsvWriter('output', `${context.output}/${TASK_ID}-${context.dates.start}-${context.dates.end}.csv`, { batch_size: 100000, logs: false });
55
- //
56
- // Export the data
57
- let counter = 0;
58
- message(`A aguardar o resultado da pesquisa...`);
59
- const result = {};
60
- for await (const doc of stream) {
61
- const document = doc;
62
- //
63
- // Prepare the result key
64
- const operationalDate = Dates
65
- .fromUnixTimestamp(document.created_at)
66
- .operational_date;
67
- const resultKey = `${operationalDate}:${document.pattern_id}`;
68
- //
69
- // Update the result with the current document
70
- if (!result[resultKey]) {
71
- result[resultKey] = {
72
- date: operationalDate,
73
- pattern_id: document.pattern_id,
74
- validations: 0,
75
- };
76
- }
77
- result[resultKey].validations += 1;
78
- if (counter % 1000 === 0)
79
- message(`Processados ${counter} documentos até agora...`);
80
- counter++;
81
- //
82
- }
83
- message(`A escrever os resultados no ficheiro CSV...`);
84
- await csvWriter.write(Object.values(result));
85
- await csvWriter.flush();
86
- //
87
- }
@@ -1,5 +0,0 @@
1
- import { type TaskProps } from '../../types.js';
2
- /**
3
- * Export Validations By Stop By Pattern data applying the given filters.
4
- */
5
- export declare function exportValidationsByStopByPattern({ context, message }: TaskProps): Promise<void>;
@@ -1,5 +0,0 @@
1
- import { type TaskProps } from '../../types.js';
2
- /**
3
- * Export Validations By Stop By Trip data applying the given filters.
4
- */
5
- export declare function exportValidationsByStopByTrip({ context, message }: TaskProps): Promise<void>;
@@ -1,88 +0,0 @@
1
- /* * */
2
- import { Dates } from '@tmlmobilidade/dates';
3
- import { simplifiedApexValidations } from '@tmlmobilidade/interfaces';
4
- import { CsvWriter } from '@tmlmobilidade/writers';
5
- import fs from 'node:fs';
6
- /* * */
7
- const TASK_ID = 'validations-by-stop-by-trip';
8
- /**
9
- * Export Validations By Stop By Trip data applying the given filters.
10
- */
11
- export async function exportValidationsByStopByTrip({ context, message }) {
12
- //
13
- message('A iniciar a exportação de Validações APEX por Paragem e por Viagem...');
14
- //
15
- // Prepare the filter params
16
- const filterQuery = {
17
- is_passenger: true,
18
- };
19
- filterQuery.created_at = {
20
- $gte: Dates
21
- .fromOperationalDate(context.dates.start, 'Europe/Lisbon')
22
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
23
- .unix_timestamp,
24
- $lt: Dates
25
- .fromOperationalDate(context.dates.end, 'Europe/Lisbon')
26
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
27
- .unix_timestamp,
28
- };
29
- if (context.filters.agency_ids.length) {
30
- filterQuery.agency_id = { $in: context.filters.agency_ids };
31
- }
32
- if (context.filters.line_ids.length) {
33
- filterQuery.line_id = { $in: context.filters.line_ids };
34
- }
35
- if (context.filters.pattern_ids.length) {
36
- filterQuery.pattern_id = { $in: context.filters.pattern_ids };
37
- }
38
- if (context.filters.stop_ids.length) {
39
- filterQuery.stop_id = { $in: context.filters.stop_ids };
40
- }
41
- if (context.filters.vehicle_ids.length) {
42
- filterQuery.vehicle_id = { $in: context.filters.vehicle_ids };
43
- }
44
- //
45
- // Setup a database stream to export data
46
- message(`A iniciar ligação à base de dados...`);
47
- const simplifiedApexValidationsCollection = await simplifiedApexValidations.getCollection();
48
- const stream = simplifiedApexValidationsCollection.find(filterQuery).stream();
49
- //
50
- // Prepare the output directory and CSV writer
51
- message(`A preparar a pasta para guardar os resultados...`);
52
- if (!fs.existsSync(context.output))
53
- fs.mkdirSync(context.output, { recursive: true });
54
- const csvWriter = new CsvWriter('output', `${context.output}/${TASK_ID}-${context.dates.start}-${context.dates.end}.csv`, { batch_size: 100000, logs: false });
55
- //
56
- // Export the data
57
- let counter = 0;
58
- message(`A aguardar o resultado da pesquisa...`);
59
- const result = {};
60
- for await (const doc of stream) {
61
- const document = doc;
62
- //
63
- // Prepare the result key
64
- const operationalDate = Dates
65
- .fromUnixTimestamp(document.created_at)
66
- .operational_date;
67
- const resultKey = `${operationalDate}:${document.stop_id}:${document.trip_id}`;
68
- //
69
- // Update the result with the current document
70
- if (!result[resultKey]) {
71
- result[resultKey] = {
72
- date: operationalDate,
73
- stop_id: document.stop_id,
74
- trip_id: document.trip_id,
75
- validations: 0,
76
- };
77
- }
78
- result[resultKey].validations += 1;
79
- if (counter % 1000 === 0)
80
- message(`Processados ${counter} documentos até agora...`);
81
- counter++;
82
- //
83
- }
84
- message(`A escrever os resultados no ficheiro CSV...`);
85
- await csvWriter.write(Object.values(result));
86
- await csvWriter.flush();
87
- //
88
- }
@@ -1,5 +0,0 @@
1
- import { type TaskProps } from '../../types.js';
2
- /**
3
- * Export Validations By Stop data applying the given filters.
4
- */
5
- export declare function exportValidationsByStop({ context, message }: TaskProps): Promise<void>;
@@ -1,87 +0,0 @@
1
- /* * */
2
- import { Dates } from '@tmlmobilidade/dates';
3
- import { simplifiedApexValidations } from '@tmlmobilidade/interfaces';
4
- import { CsvWriter } from '@tmlmobilidade/writers';
5
- import fs from 'node:fs';
6
- /* * */
7
- const TASK_ID = 'validations-by-stop';
8
- /**
9
- * Export Validations By Stop data applying the given filters.
10
- */
11
- export async function exportValidationsByStop({ context, message }) {
12
- //
13
- message('A iniciar a exportação de Validações APEX por Paragem...');
14
- //
15
- // Prepare the filter params
16
- const filterQuery = {
17
- is_passenger: true,
18
- };
19
- filterQuery.created_at = {
20
- $gte: Dates
21
- .fromOperationalDate(context.dates.start, 'Europe/Lisbon')
22
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
23
- .unix_timestamp,
24
- $lt: Dates
25
- .fromOperationalDate(context.dates.end, 'Europe/Lisbon')
26
- .set({ hour: 4, millisecond: 0, minute: 0, second: 0 })
27
- .unix_timestamp,
28
- };
29
- if (context.filters.agency_ids.length) {
30
- filterQuery.agency_id = { $in: context.filters.agency_ids };
31
- }
32
- if (context.filters.line_ids.length) {
33
- filterQuery.line_id = { $in: context.filters.line_ids };
34
- }
35
- if (context.filters.pattern_ids.length) {
36
- filterQuery.pattern_id = { $in: context.filters.pattern_ids };
37
- }
38
- if (context.filters.stop_ids.length) {
39
- filterQuery.stop_id = { $in: context.filters.stop_ids };
40
- }
41
- if (context.filters.vehicle_ids.length) {
42
- filterQuery.vehicle_id = { $in: context.filters.vehicle_ids };
43
- }
44
- //
45
- // Setup a database stream to export data
46
- message(`A iniciar ligação à base de dados...`);
47
- const simplifiedApexValidationsCollection = await simplifiedApexValidations.getCollection();
48
- const stream = simplifiedApexValidationsCollection.find(filterQuery).stream();
49
- //
50
- // Prepare the output directory and CSV writer
51
- message(`A preparar a pasta para guardar os resultados...`);
52
- if (!fs.existsSync(context.output))
53
- fs.mkdirSync(context.output, { recursive: true });
54
- const csvWriter = new CsvWriter('output', `${context.output}/${TASK_ID}-${context.dates.start}-${context.dates.end}.csv`, { batch_size: 100000, logs: false });
55
- //
56
- // Export the data
57
- let counter = 0;
58
- message(`A aguardar o resultado da pesquisa...`);
59
- const result = {};
60
- for await (const doc of stream) {
61
- const document = doc;
62
- //
63
- // Prepare the result key
64
- const operationalDate = Dates
65
- .fromUnixTimestamp(document.created_at)
66
- .operational_date;
67
- const resultKey = `${operationalDate}:${document.stop_id}`;
68
- //
69
- // Update the result with the current document
70
- if (!result[resultKey]) {
71
- result[resultKey] = {
72
- date: operationalDate,
73
- stop_id: document.stop_id,
74
- validations: 0,
75
- };
76
- }
77
- result[resultKey].validations += 1;
78
- if (counter % 1000 === 0)
79
- message(`Processados ${counter} documentos até agora...`);
80
- counter++;
81
- //
82
- }
83
- message(`A escrever os resultados no ficheiro CSV...`);
84
- await csvWriter.write(Object.values(result));
85
- await csvWriter.flush();
86
- //
87
- }