firestore-batch-updater 1.12.0 → 1.13.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
@@ -29,6 +29,7 @@
29
29
  - 고유값 조회 - `distinct()`로 특정 필드의 중복 없는 값 목록 조회
30
30
  - JSON 내보내기/가져오기 - `toJSON()` / `fromJSON()`으로 문서 JSON 파일 내보내기/가져오기
31
31
  - 그룹별 개수 조회 - `countBy()`로 특정 필드 값별 문서 수 집계
32
+ - 랜덤 샘플링 - `sample()`로 쿼리 결과에서 랜덤 문서 추출
32
33
  - FieldValue 지원 - `increment()`, `arrayUnion()`, `delete()`, `serverTimestamp()` 등 사용 가능
33
34
  - 서브컬렉션 & 컬렉션 그룹 - 서브컬렉션 쿼리 또는 동일 이름의 모든 컬렉션 쿼리
34
35
  - Dry Run 모드 - 실제 변경 없이 작업 시뮬레이션
@@ -123,6 +124,7 @@ console.log(`${result.successCount}개 문서 업데이트 완료`);
123
124
  | `transform(fn, options?)` | 커스텀 함수로 문서 변환 | `TransformResult` |
124
125
  | `copyTo(target, options?)` | 다른 컬렉션으로 문서 복사/이동 | `CopyToResult` |
125
126
  | `distinct(field)` | 특정 필드의 고유값 조회 | `any[]` |
127
+ | `sample(n)` | 매칭 문서에서 랜덤 샘플 추출 | `{ id, data }[]` |
126
128
  | `toJSON(path, options?)` | 문서를 JSON 파일로 내보내기 | `ToJSONResult` |
127
129
  | `fromJSON(path, options?)` | JSON 파일에서 문서 가져오기 | `FromJSONResult` |
128
130
  | `countBy(field)` | 필드 값별 문서 수 집계 | `CountByResult` |
@@ -779,6 +781,26 @@ await updater.collection("users").toJSON("./backup.json");
779
781
  await updater.collection("users_backup").fromJSON("./backup.json");
780
782
  ```
781
783
 
784
+ ### 랜덤 샘플링
785
+
786
+ ```typescript
787
+ // 랜덤으로 5개 문서 추출
788
+ const samples = await updater.collection("users").sample(5);
789
+ samples.forEach(doc => console.log(doc.id, doc.data.name));
790
+
791
+ // 필터된 결과에서 랜덤 샘플
792
+ const activeUsers = await updater
793
+ .collection("users")
794
+ .where("status", "==", "active")
795
+ .sample(3);
796
+
797
+ // select와 함께 사용하여 메모리 효율 극대화
798
+ const randomProducts = await updater
799
+ .collection("products")
800
+ .select("name", "price")
801
+ .sample(10);
802
+ ```
803
+
782
804
  ### Dry Run 모드
783
805
 
784
806
  ```typescript
package/README.md CHANGED
@@ -29,6 +29,7 @@ English | [한국어](./README.ko.md)
29
29
  - Distinct values - Use `distinct()` to get unique field values from matching documents
30
30
  - JSON export/import - Use `toJSON()` / `fromJSON()` to export/import documents as JSON
31
31
  - Group counting - Use `countBy()` to count documents grouped by field value
32
+ - Random sampling - Use `sample()` to get random documents from query results
32
33
  - FieldValue support - Use `increment()`, `arrayUnion()`, `delete()`, `serverTimestamp()`, etc.
33
34
  - Subcollection & Collection Group - Query subcollections or all collections with the same name
34
35
  - Dry run mode - Simulate operations without making changes
@@ -123,6 +124,7 @@ console.log(`Updated ${result.successCount} documents`);
123
124
  | `transform(fn, options?)` | Transform docs with custom function | `TransformResult` |
124
125
  | `copyTo(target, options?)` | Copy/move docs to another collection | `CopyToResult` |
125
126
  | `distinct(field)` | Get unique values of a field | `any[]` |
127
+ | `sample(n)` | Get random sample of matching documents | `{ id, data }[]` |
126
128
  | `toJSON(path, options?)` | Export documents to JSON file | `ToJSONResult` |
127
129
  | `fromJSON(path, options?)` | Import documents from JSON file | `FromJSONResult` |
128
130
  | `countBy(field)` | Count documents grouped by field value | `CountByResult` |
@@ -792,6 +794,26 @@ await updater.collection("users").toJSON("./backup.json");
792
794
  await updater.collection("users_backup").fromJSON("./backup.json");
793
795
  ```
794
796
 
797
+ ### Random Sampling
798
+
799
+ ```typescript
800
+ // Get 5 random documents
801
+ const samples = await updater.collection("users").sample(5);
802
+ samples.forEach(doc => console.log(doc.id, doc.data.name));
803
+
804
+ // Random sample from filtered results
805
+ const activeUsers = await updater
806
+ .collection("users")
807
+ .where("status", "==", "active")
808
+ .sample(3);
809
+
810
+ // With select for memory efficiency
811
+ const randomProducts = await updater
812
+ .collection("products")
813
+ .select("name", "price")
814
+ .sample(10);
815
+ ```
816
+
795
817
  ### Dry Run Mode
796
818
 
797
819
  ```typescript
package/dist/index.d.mts CHANGED
@@ -744,6 +744,15 @@ declare class BatchUpdater {
744
744
  * @returns Array of unique values
745
745
  */
746
746
  distinct(field: string): Promise<any[]>;
747
+ /**
748
+ * Get a random sample of matching documents
749
+ * @param n - Number of documents to sample
750
+ * @returns Array of randomly selected documents with { id, data }
751
+ */
752
+ sample(n: number): Promise<{
753
+ id: string;
754
+ data: Record<string, any>;
755
+ }[]>;
747
756
  /**
748
757
  * Export matching documents to a JSON file
749
758
  * @param filePath - Path for the output JSON file
package/dist/index.d.ts CHANGED
@@ -744,6 +744,15 @@ declare class BatchUpdater {
744
744
  * @returns Array of unique values
745
745
  */
746
746
  distinct(field: string): Promise<any[]>;
747
+ /**
748
+ * Get a random sample of matching documents
749
+ * @param n - Number of documents to sample
750
+ * @returns Array of randomly selected documents with { id, data }
751
+ */
752
+ sample(n: number): Promise<{
753
+ id: string;
754
+ data: Record<string, any>;
755
+ }[]>;
747
756
  /**
748
757
  * Export matching documents to a JSON file
749
758
  * @param filePath - Path for the output JSON file
package/dist/index.js CHANGED
@@ -1263,6 +1263,34 @@ var BatchUpdater = class {
1263
1263
  }
1264
1264
  return values;
1265
1265
  }
1266
+ /**
1267
+ * Get a random sample of matching documents
1268
+ * @param n - Number of documents to sample
1269
+ * @returns Array of randomly selected documents with { id, data }
1270
+ */
1271
+ async sample(n) {
1272
+ this.validateSetup();
1273
+ if (!Number.isInteger(n) || n < 1) {
1274
+ throw new Error("Sample size must be a positive integer");
1275
+ }
1276
+ const query = this.buildQuery();
1277
+ const snapshot = await query.get();
1278
+ if (snapshot.empty) {
1279
+ return [];
1280
+ }
1281
+ const docs = snapshot.docs.map((doc) => ({
1282
+ id: doc.id,
1283
+ data: doc.data()
1284
+ }));
1285
+ if (docs.length <= n) {
1286
+ return docs;
1287
+ }
1288
+ for (let i = docs.length - 1; i > docs.length - 1 - n; i--) {
1289
+ const j = Math.floor(Math.random() * (i + 1));
1290
+ [docs[i], docs[j]] = [docs[j], docs[i]];
1291
+ }
1292
+ return docs.slice(docs.length - n);
1293
+ }
1266
1294
  /**
1267
1295
  * Export matching documents to a JSON file
1268
1296
  * @param filePath - Path for the output JSON file
package/dist/index.mjs CHANGED
@@ -1218,6 +1218,34 @@ var BatchUpdater = class {
1218
1218
  }
1219
1219
  return values;
1220
1220
  }
1221
+ /**
1222
+ * Get a random sample of matching documents
1223
+ * @param n - Number of documents to sample
1224
+ * @returns Array of randomly selected documents with { id, data }
1225
+ */
1226
+ async sample(n) {
1227
+ this.validateSetup();
1228
+ if (!Number.isInteger(n) || n < 1) {
1229
+ throw new Error("Sample size must be a positive integer");
1230
+ }
1231
+ const query = this.buildQuery();
1232
+ const snapshot = await query.get();
1233
+ if (snapshot.empty) {
1234
+ return [];
1235
+ }
1236
+ const docs = snapshot.docs.map((doc) => ({
1237
+ id: doc.id,
1238
+ data: doc.data()
1239
+ }));
1240
+ if (docs.length <= n) {
1241
+ return docs;
1242
+ }
1243
+ for (let i = docs.length - 1; i > docs.length - 1 - n; i--) {
1244
+ const j = Math.floor(Math.random() * (i + 1));
1245
+ [docs[i], docs[j]] = [docs[j], docs[i]];
1246
+ }
1247
+ return docs.slice(docs.length - n);
1248
+ }
1221
1249
  /**
1222
1250
  * Export matching documents to a JSON file
1223
1251
  * @param filePath - Path for the output JSON file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firestore-batch-updater",
3
- "version": "1.12.0",
3
+ "version": "1.13.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",