firestore-batch-updater 1.16.0 → 1.17.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.ko.md CHANGED
@@ -21,6 +21,7 @@
21
21
  - 전체 문서 조회 - `getAll()`로 매칭되는 모든 문서 데이터 조회
22
22
  - 집계 쿼리 - `aggregate()`로 서버 사이드 `sum`, `average`, `count` 연산
23
23
  - 간편 집계 - `sum()`, `avg()`, `min()`, `max()`로 단일 필드 간편 집계
24
+ - 통합 통계 - `fieldStats()`로 sum/avg/min/max/count 한 번에 조회
24
25
  - 커서 페이지네이션 - `paginate()`로 메모리 효율적인 페이지 단위 조회
25
26
  - ID 직접 조회 - `getOne()`으로 문서 ID로 빠른 조회
26
27
  - 벌크 작업 - `bulkCreate()`, `bulkUpdate()`, `bulkDelete()`로 여러 문서에 각기 다른 데이터로 효율적 처리
@@ -121,6 +122,7 @@ console.log(`${result.successCount}개 문서 업데이트 완료`);
121
122
  | `avg(field)` | 숫자 필드 평균 조회 | `number \| null` |
122
123
  | `min(field)` | 필드 최소값 조회 | `any` |
123
124
  | `max(field)` | 필드 최대값 조회 | `any` |
125
+ | `fieldStats(field)` | sum/avg/min/max/count 한 번에 조회 | `FieldStatsResult` |
124
126
  | `paginate(options)` | 커서 기반 페이지네이션 | `PaginateResult` |
125
127
  | `bulkCreate(docs, options?)` | 여러 문서를 각기 다른 데이터로 생성 | `BulkCreateResult` |
126
128
  | `bulkUpdate(updates, options?)` | 여러 문서에 각기 다른 데이터 업데이트 | `BulkUpdateResult` |
@@ -182,6 +184,7 @@ console.log(`${result.successCount}개 문서 업데이트 완료`);
182
184
  | `UpsertResult` | `successCount`, `failureCount`, `totalCount`, `failedDocIds?`, `logFilePath?` |
183
185
  | `DeleteResult` | `successCount`, `failureCount`, `totalCount`, `deletedIds[]`, `failedDocIds?`, `logFilePath?` |
184
186
  | `AggregateResult` | `{ [alias]: number \| null }` |
187
+ | `FieldStatsResult` | `sum`, `avg`, `min`, `max`, `count` |
185
188
  | `PaginateResult` | `docs[]`, `nextCursor`, `hasMore` |
186
189
  | `BulkCreateResult` | `successCount`, `failureCount`, `totalCount`, `createdIds[]`, `failedDocIds?`, `logFilePath?` |
187
190
  | `BulkUpdateResult` | `successCount`, `failureCount`, `totalCount`, `failedDocIds?`, `logFilePath?` |
@@ -569,6 +572,26 @@ const maxScore = await updater
569
572
 
570
573
  > 참고: 한 필드에 `where()`를 걸고 다른 필드에 `min()/max()`를 사용할 경우 Firestore 복합 인덱스가 필요할 수 있습니다. `FAILED_PRECONDITION` 오류가 발생하면 오류 메시지의 링크를 통해 인덱스를 생성하세요.
571
574
 
575
+ ### 통합 필드 통계
576
+
577
+ ```typescript
578
+ // 한 필드의 sum, avg, min, max, count를 한 번에 조회
579
+ const stats = await updater.collection("products").fieldStats("price");
580
+ console.log(stats);
581
+ // { sum: 12500, avg: 250, min: 50, max: 500, count: 50 }
582
+
583
+ // 대시보드에서 유용
584
+ const orderStats = await updater
585
+ .collection("orders")
586
+ .where("status", "==", "completed")
587
+ .fieldStats("amount");
588
+
589
+ console.log(`총 매출: ${orderStats.sum}원`);
590
+ console.log(`평균 주문액: ${orderStats.avg}원`);
591
+ console.log(`주문 수: ${orderStats.count}건`);
592
+ console.log(`범위: ${orderStats.min}원 - ${orderStats.max}원`);
593
+ ```
594
+
572
595
  ### 커서 기반 페이지네이션
573
596
 
574
597
  ```typescript
package/README.md CHANGED
@@ -21,6 +21,7 @@ English | [한국어](./README.ko.md)
21
21
  - Get all documents - Use `getAll()` to retrieve all matching documents with data
22
22
  - Aggregation - Use `aggregate()` for server-side `sum`, `average`, and `count` operations
23
23
  - Quick aggregation - Use `sum()`, `avg()`, `min()`, `max()` for simple single-field aggregation
24
+ - Combined stats - Use `fieldStats()` to get sum/avg/min/max/count in one call
24
25
  - Cursor pagination - Use `paginate()` for memory-efficient page-by-page iteration
25
26
  - Direct ID lookup - Use `getOne()` for fast document retrieval by ID
26
27
  - Bulk operations - Use `bulkCreate()`, `bulkUpdate()`, `bulkDelete()` for efficient multi-document operations with different data each
@@ -121,6 +122,7 @@ console.log(`Updated ${result.successCount} documents`);
121
122
  | `avg(field)` | Get average of a numeric field | `number \| null` |
122
123
  | `min(field)` | Get minimum value of a field | `any` |
123
124
  | `max(field)` | Get maximum value of a field | `any` |
125
+ | `fieldStats(field)` | Get sum/avg/min/max/count for a field in one call | `FieldStatsResult` |
124
126
  | `paginate(options)` | Cursor-based pagination | `PaginateResult` |
125
127
  | `bulkCreate(docs, options?)` | Create multiple docs with different data | `BulkCreateResult` |
126
128
  | `bulkUpdate(updates, options?)` | Update multiple docs with different data | `BulkUpdateResult` |
@@ -182,6 +184,7 @@ All write operations support an optional `options` parameter:
182
184
  | `UpsertResult` | `successCount`, `failureCount`, `totalCount`, `failedDocIds?`, `logFilePath?` |
183
185
  | `DeleteResult` | `successCount`, `failureCount`, `totalCount`, `deletedIds[]`, `failedDocIds?`, `logFilePath?` |
184
186
  | `AggregateResult` | `{ [alias]: number \| null }` |
187
+ | `FieldStatsResult` | `sum`, `avg`, `min`, `max`, `count` |
185
188
  | `PaginateResult` | `docs[]`, `nextCursor`, `hasMore` |
186
189
  | `BulkCreateResult` | `successCount`, `failureCount`, `totalCount`, `createdIds[]`, `failedDocIds?`, `logFilePath?` |
187
190
  | `BulkUpdateResult` | `successCount`, `failureCount`, `totalCount`, `failedDocIds?`, `logFilePath?` |
@@ -593,6 +596,26 @@ const maxScore = await updater
593
596
 
594
597
  > Note: Combining `where()` on one field with `min()/max()` on a different field may require a Firestore composite index. If you see a `FAILED_PRECONDITION` error, follow the link in the error message to create the required index.
595
598
 
599
+ ### Combined Field Stats
600
+
601
+ ```typescript
602
+ // Get sum, avg, min, max, count for a single field in one call
603
+ const stats = await updater.collection("products").fieldStats("price");
604
+ console.log(stats);
605
+ // { sum: 12500, avg: 250, min: 50, max: 500, count: 50 }
606
+
607
+ // Useful for dashboards
608
+ const orderStats = await updater
609
+ .collection("orders")
610
+ .where("status", "==", "completed")
611
+ .fieldStats("amount");
612
+
613
+ console.log(`Total revenue: $${orderStats.sum}`);
614
+ console.log(`Average order: $${orderStats.avg}`);
615
+ console.log(`Order count: ${orderStats.count}`);
616
+ console.log(`Range: $${orderStats.min} - $${orderStats.max}`);
617
+ ```
618
+
596
619
  ### Cursor-Based Pagination
597
620
 
598
621
  ```typescript
package/dist/index.d.mts CHANGED
@@ -455,6 +455,17 @@ interface CopyToResult {
455
455
  copiedIds: string[];
456
456
  failedDocIds?: string[];
457
457
  }
458
+ /**
459
+ * Result of fieldStats operation
460
+ * Combined statistics for a single field
461
+ */
462
+ interface FieldStatsResult {
463
+ sum: number | null;
464
+ avg: number | null;
465
+ min: any;
466
+ max: any;
467
+ count: number;
468
+ }
458
469
  /**
459
470
  * Result of countBy operation
460
471
  */
@@ -669,6 +680,13 @@ declare class BatchUpdater {
669
680
  * @returns Maximum field value, or null if no documents match
670
681
  */
671
682
  max(field: string): Promise<any>;
683
+ /**
684
+ * Get combined statistics (sum, avg, min, max, count) for a single field
685
+ * Convenience method that runs aggregate + min + max in parallel
686
+ * @param field - Field path to compute statistics for
687
+ * @returns Object with sum, avg, min, max, count
688
+ */
689
+ fieldStats(field: string): Promise<FieldStatsResult>;
672
690
  /**
673
691
  * Get documents with cursor-based pagination
674
692
  * @param options - Pagination options (pageSize, startAfter cursor)
@@ -897,4 +915,4 @@ declare function isValidUpdateData(value: any): value is Record<string, any>;
897
915
  */
898
916
  declare function formatError(error: unknown, context?: string): string;
899
917
 
900
- export { type AggregateResult, type AggregateSpec, BatchUpdater, type BulkCreateInput, type BulkCreateOptions, type BulkCreateResult, type BulkDeleteOptions, type BulkDeleteResult, type BulkUpdateInput, type BulkUpdateOptions, type BulkUpdateResult, type CopyToOptions, type CopyToResult, type CountByResult, type CountResult, type CreateDocumentInput, type CreateOneResult, type CreateOptions, type CreateResult, type DeleteOptions, type DeleteResult, type DocumentSnapshot, type DryRunResult, type FieldValueResult, type FromJSONOptions, type FromJSONResult, type LogEntry, type LogOptions, type OperationLog, type OrderByCondition, type PaginateOptions, type PaginateResult, type PreviewResult, type ProgressInfo, type ToJSONOptions, type ToJSONResult, type TransformFn, type TransformOptions, type TransformResult, type UpdateOptions, type UpdateResult, type UpsertOptions, type UpsertResult, type WhereCondition, calculateProgress, createLogCollector, formatError, formatOperationLog, getAffectedFields, isValidUpdateData, mergeUpdateData, writeOperationLog };
918
+ export { type AggregateResult, type AggregateSpec, BatchUpdater, type BulkCreateInput, type BulkCreateOptions, type BulkCreateResult, type BulkDeleteOptions, type BulkDeleteResult, type BulkUpdateInput, type BulkUpdateOptions, type BulkUpdateResult, type CopyToOptions, type CopyToResult, type CountByResult, type CountResult, type CreateDocumentInput, type CreateOneResult, type CreateOptions, type CreateResult, type DeleteOptions, type DeleteResult, type DocumentSnapshot, type DryRunResult, type FieldStatsResult, type FieldValueResult, type FromJSONOptions, type FromJSONResult, type LogEntry, type LogOptions, type OperationLog, type OrderByCondition, type PaginateOptions, type PaginateResult, type PreviewResult, type ProgressInfo, type ToJSONOptions, type ToJSONResult, type TransformFn, type TransformOptions, type TransformResult, type UpdateOptions, type UpdateResult, type UpsertOptions, type UpsertResult, type WhereCondition, calculateProgress, createLogCollector, formatError, formatOperationLog, getAffectedFields, isValidUpdateData, mergeUpdateData, writeOperationLog };
package/dist/index.d.ts CHANGED
@@ -455,6 +455,17 @@ interface CopyToResult {
455
455
  copiedIds: string[];
456
456
  failedDocIds?: string[];
457
457
  }
458
+ /**
459
+ * Result of fieldStats operation
460
+ * Combined statistics for a single field
461
+ */
462
+ interface FieldStatsResult {
463
+ sum: number | null;
464
+ avg: number | null;
465
+ min: any;
466
+ max: any;
467
+ count: number;
468
+ }
458
469
  /**
459
470
  * Result of countBy operation
460
471
  */
@@ -669,6 +680,13 @@ declare class BatchUpdater {
669
680
  * @returns Maximum field value, or null if no documents match
670
681
  */
671
682
  max(field: string): Promise<any>;
683
+ /**
684
+ * Get combined statistics (sum, avg, min, max, count) for a single field
685
+ * Convenience method that runs aggregate + min + max in parallel
686
+ * @param field - Field path to compute statistics for
687
+ * @returns Object with sum, avg, min, max, count
688
+ */
689
+ fieldStats(field: string): Promise<FieldStatsResult>;
672
690
  /**
673
691
  * Get documents with cursor-based pagination
674
692
  * @param options - Pagination options (pageSize, startAfter cursor)
@@ -897,4 +915,4 @@ declare function isValidUpdateData(value: any): value is Record<string, any>;
897
915
  */
898
916
  declare function formatError(error: unknown, context?: string): string;
899
917
 
900
- export { type AggregateResult, type AggregateSpec, BatchUpdater, type BulkCreateInput, type BulkCreateOptions, type BulkCreateResult, type BulkDeleteOptions, type BulkDeleteResult, type BulkUpdateInput, type BulkUpdateOptions, type BulkUpdateResult, type CopyToOptions, type CopyToResult, type CountByResult, type CountResult, type CreateDocumentInput, type CreateOneResult, type CreateOptions, type CreateResult, type DeleteOptions, type DeleteResult, type DocumentSnapshot, type DryRunResult, type FieldValueResult, type FromJSONOptions, type FromJSONResult, type LogEntry, type LogOptions, type OperationLog, type OrderByCondition, type PaginateOptions, type PaginateResult, type PreviewResult, type ProgressInfo, type ToJSONOptions, type ToJSONResult, type TransformFn, type TransformOptions, type TransformResult, type UpdateOptions, type UpdateResult, type UpsertOptions, type UpsertResult, type WhereCondition, calculateProgress, createLogCollector, formatError, formatOperationLog, getAffectedFields, isValidUpdateData, mergeUpdateData, writeOperationLog };
918
+ export { type AggregateResult, type AggregateSpec, BatchUpdater, type BulkCreateInput, type BulkCreateOptions, type BulkCreateResult, type BulkDeleteOptions, type BulkDeleteResult, type BulkUpdateInput, type BulkUpdateOptions, type BulkUpdateResult, type CopyToOptions, type CopyToResult, type CountByResult, type CountResult, type CreateDocumentInput, type CreateOneResult, type CreateOptions, type CreateResult, type DeleteOptions, type DeleteResult, type DocumentSnapshot, type DryRunResult, type FieldStatsResult, type FieldValueResult, type FromJSONOptions, type FromJSONResult, type LogEntry, type LogOptions, type OperationLog, type OrderByCondition, type PaginateOptions, type PaginateResult, type PreviewResult, type ProgressInfo, type ToJSONOptions, type ToJSONResult, type TransformFn, type TransformOptions, type TransformResult, type UpdateOptions, type UpdateResult, type UpsertOptions, type UpsertResult, type WhereCondition, calculateProgress, createLogCollector, formatError, formatOperationLog, getAffectedFields, isValidUpdateData, mergeUpdateData, writeOperationLog };
package/dist/index.js CHANGED
@@ -547,6 +547,34 @@ var BatchUpdater = class {
547
547
  const value = this.getNestedValue(snapshot.docs[0].data(), field);
548
548
  return value ?? null;
549
549
  }
550
+ /**
551
+ * Get combined statistics (sum, avg, min, max, count) for a single field
552
+ * Convenience method that runs aggregate + min + max in parallel
553
+ * @param field - Field path to compute statistics for
554
+ * @returns Object with sum, avg, min, max, count
555
+ */
556
+ async fieldStats(field) {
557
+ this.validateSetup();
558
+ if (!field || typeof field !== "string") {
559
+ throw new Error("Field is required for fieldStats operation");
560
+ }
561
+ const [aggResult, minVal, maxVal] = await Promise.all([
562
+ this.aggregate({
563
+ _sum: { op: "sum", field },
564
+ _avg: { op: "average", field },
565
+ _count: { op: "count" }
566
+ }),
567
+ this.min(field),
568
+ this.max(field)
569
+ ]);
570
+ return {
571
+ sum: aggResult._sum,
572
+ avg: aggResult._avg,
573
+ min: minVal,
574
+ max: maxVal,
575
+ count: aggResult._count ?? 0
576
+ };
577
+ }
550
578
  /**
551
579
  * Get documents with cursor-based pagination
552
580
  * @param options - Pagination options (pageSize, startAfter cursor)
package/dist/index.mjs CHANGED
@@ -502,6 +502,34 @@ var BatchUpdater = class {
502
502
  const value = this.getNestedValue(snapshot.docs[0].data(), field);
503
503
  return value ?? null;
504
504
  }
505
+ /**
506
+ * Get combined statistics (sum, avg, min, max, count) for a single field
507
+ * Convenience method that runs aggregate + min + max in parallel
508
+ * @param field - Field path to compute statistics for
509
+ * @returns Object with sum, avg, min, max, count
510
+ */
511
+ async fieldStats(field) {
512
+ this.validateSetup();
513
+ if (!field || typeof field !== "string") {
514
+ throw new Error("Field is required for fieldStats operation");
515
+ }
516
+ const [aggResult, minVal, maxVal] = await Promise.all([
517
+ this.aggregate({
518
+ _sum: { op: "sum", field },
519
+ _avg: { op: "average", field },
520
+ _count: { op: "count" }
521
+ }),
522
+ this.min(field),
523
+ this.max(field)
524
+ ]);
525
+ return {
526
+ sum: aggResult._sum,
527
+ avg: aggResult._avg,
528
+ min: minVal,
529
+ max: maxVal,
530
+ count: aggResult._count ?? 0
531
+ };
532
+ }
505
533
  /**
506
534
  * Get documents with cursor-based pagination
507
535
  * @param options - Pagination options (pageSize, startAfter cursor)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firestore-batch-updater",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "Batch update Firestore documents with query-based filtering and preview",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",