firebase-rest-firestore 0.1.0 → 0.2.1
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.md +528 -66
- package/dist/client.d.ts +240 -0
- package/dist/client.js +461 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -1
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ Firebase Firestore REST API client for Edge runtime environments like Cloudflare
|
|
|
10
10
|
- Token caching for better performance
|
|
11
11
|
- Simple and intuitive API
|
|
12
12
|
- Explicit configuration without hidden environment variable dependencies
|
|
13
|
+
- Firebase Admin SDK compatible interface (v0.2.0+)
|
|
14
|
+
- Lazy configuration validation for Next.js compatibility (v0.2.1+)
|
|
13
15
|
|
|
14
16
|
## Installation
|
|
15
17
|
|
|
@@ -63,6 +65,83 @@ console.log("Games with score > 50:", userGames);
|
|
|
63
65
|
await firestore.delete("games", game.id);
|
|
64
66
|
```
|
|
65
67
|
|
|
68
|
+
### Firebase Admin SDK Compatible Interface (v0.2.0+)
|
|
69
|
+
|
|
70
|
+
From version 0.2.0, firebase-rest-firestore provides a Firebase Admin SDK compatible interface:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
74
|
+
|
|
75
|
+
// Create a client with your configuration
|
|
76
|
+
const firestore = createFirestoreClient({
|
|
77
|
+
projectId: "your-project-id",
|
|
78
|
+
privateKey: "your-private-key",
|
|
79
|
+
clientEmail: "your-client-email",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Create a document with auto-generated ID
|
|
83
|
+
const gameRef = firestore.collection("games").doc();
|
|
84
|
+
await gameRef.set({
|
|
85
|
+
name: "New Game",
|
|
86
|
+
createdAt: new Date(),
|
|
87
|
+
score: 100,
|
|
88
|
+
active: true,
|
|
89
|
+
});
|
|
90
|
+
console.log("Created game ID:", gameRef.id);
|
|
91
|
+
|
|
92
|
+
// Create a document with specific ID
|
|
93
|
+
await firestore.collection("games").doc("game123").set({
|
|
94
|
+
name: "Specific Game",
|
|
95
|
+
createdAt: new Date(),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Get a document
|
|
99
|
+
const gameDoc = await firestore.doc("games/game123").get();
|
|
100
|
+
if (gameDoc.exists) {
|
|
101
|
+
console.log("Fetched game:", gameDoc.data());
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Update a document
|
|
105
|
+
await firestore.collection("games").doc("game123").update({
|
|
106
|
+
name: "Updated Game Name",
|
|
107
|
+
updatedAt: new Date(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Query documents
|
|
111
|
+
const querySnapshot = await firestore
|
|
112
|
+
.collection("games")
|
|
113
|
+
.where("score", ">", 50)
|
|
114
|
+
.where("active", "==", true)
|
|
115
|
+
.orderBy("score", "desc")
|
|
116
|
+
.limit(10)
|
|
117
|
+
.get();
|
|
118
|
+
|
|
119
|
+
// Process query results
|
|
120
|
+
const games = [];
|
|
121
|
+
querySnapshot.forEach(doc => {
|
|
122
|
+
games.push({
|
|
123
|
+
id: doc.id,
|
|
124
|
+
...doc.data(),
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
console.log("Games with score > 50:", games);
|
|
128
|
+
|
|
129
|
+
// Delete a document
|
|
130
|
+
await firestore.collection("games").doc("game123").delete();
|
|
131
|
+
|
|
132
|
+
// Working with subcollections
|
|
133
|
+
const commentRef = firestore
|
|
134
|
+
.collection("games")
|
|
135
|
+
.doc("game123")
|
|
136
|
+
.collection("comments")
|
|
137
|
+
.doc();
|
|
138
|
+
|
|
139
|
+
await commentRef.set({
|
|
140
|
+
text: "Great game!",
|
|
141
|
+
createdAt: new Date(),
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
66
145
|
## Configuration
|
|
67
146
|
|
|
68
147
|
The `FirestoreConfig` object requires the following properties:
|
|
@@ -107,64 +186,60 @@ Creates a new FirestoreClient instance with the provided configuration.
|
|
|
107
186
|
|
|
108
187
|
Helper function to load configuration from environment variables.
|
|
109
188
|
|
|
110
|
-
##
|
|
111
|
-
|
|
112
|
-
MIT
|
|
113
|
-
|
|
114
|
-
## エラーハンドリング
|
|
189
|
+
## Error Handling
|
|
115
190
|
|
|
116
|
-
Firebase REST Firestore
|
|
191
|
+
Firebase REST Firestore throws exceptions with appropriate error messages when API requests fail. Here's an example of error handling:
|
|
117
192
|
|
|
118
193
|
```typescript
|
|
119
194
|
try {
|
|
120
|
-
//
|
|
195
|
+
// Try to get a document
|
|
121
196
|
const game = await firestore.get("games", "non-existent-id");
|
|
122
197
|
|
|
123
|
-
//
|
|
198
|
+
// If document doesn't exist, null is returned
|
|
124
199
|
if (game === null) {
|
|
125
|
-
console.log("
|
|
200
|
+
console.log("Document not found");
|
|
126
201
|
return;
|
|
127
202
|
}
|
|
128
203
|
|
|
129
|
-
//
|
|
130
|
-
console.log("
|
|
204
|
+
// Process document if it exists
|
|
205
|
+
console.log("Fetched game:", game);
|
|
131
206
|
} catch (error) {
|
|
132
|
-
// API
|
|
133
|
-
console.error("Firestore
|
|
207
|
+
// Handle API errors (authentication, network, etc.)
|
|
208
|
+
console.error("Firestore error:", error.message);
|
|
134
209
|
}
|
|
135
210
|
```
|
|
136
211
|
|
|
137
|
-
|
|
212
|
+
Common error cases:
|
|
138
213
|
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
- Firestore
|
|
214
|
+
- Authentication errors (invalid credentials)
|
|
215
|
+
- Network errors
|
|
216
|
+
- Invalid query parameters
|
|
217
|
+
- Firestore rate limits
|
|
143
218
|
|
|
144
|
-
##
|
|
219
|
+
## Query Options Details
|
|
145
220
|
|
|
146
|
-
`query
|
|
221
|
+
The `query` method supports the following options for filtering, sorting, and paginating Firestore documents:
|
|
147
222
|
|
|
148
223
|
### where
|
|
149
224
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- `field`:
|
|
153
|
-
- `op`:
|
|
154
|
-
- `EQUAL`:
|
|
155
|
-
- `NOT_EQUAL`:
|
|
156
|
-
- `LESS_THAN`:
|
|
157
|
-
- `LESS_THAN_OR_EQUAL`:
|
|
158
|
-
- `GREATER_THAN`:
|
|
159
|
-
- `GREATER_THAN_OR_EQUAL`:
|
|
160
|
-
- `ARRAY_CONTAINS`:
|
|
161
|
-
- `IN`:
|
|
162
|
-
- `ARRAY_CONTAINS_ANY`:
|
|
163
|
-
- `NOT_IN`:
|
|
164
|
-
- `value`:
|
|
225
|
+
Specify multiple filter conditions. Each condition is an object with the following properties:
|
|
226
|
+
|
|
227
|
+
- `field`: The field name to filter on
|
|
228
|
+
- `op`: The comparison operator. Available values:
|
|
229
|
+
- `EQUAL`: Equal to
|
|
230
|
+
- `NOT_EQUAL`: Not equal to
|
|
231
|
+
- `LESS_THAN`: Less than
|
|
232
|
+
- `LESS_THAN_OR_EQUAL`: Less than or equal to
|
|
233
|
+
- `GREATER_THAN`: Greater than
|
|
234
|
+
- `GREATER_THAN_OR_EQUAL`: Greater than or equal to
|
|
235
|
+
- `ARRAY_CONTAINS`: Array contains
|
|
236
|
+
- `IN`: Equal to any of the specified values
|
|
237
|
+
- `ARRAY_CONTAINS_ANY`: Array contains any of the specified values
|
|
238
|
+
- `NOT_IN`: Not equal to any of the specified values
|
|
239
|
+
- `value`: The value to compare against
|
|
165
240
|
|
|
166
241
|
```typescript
|
|
167
|
-
//
|
|
242
|
+
// Query games with score > 50 and active = true
|
|
168
243
|
const games = await firestore.query("games", {
|
|
169
244
|
where: [
|
|
170
245
|
{ field: "score", op: "GREATER_THAN", value: 50 },
|
|
@@ -175,10 +250,10 @@ const games = await firestore.query("games", {
|
|
|
175
250
|
|
|
176
251
|
### orderBy
|
|
177
252
|
|
|
178
|
-
|
|
253
|
+
Specifies the field name to sort results by. Results are sorted in ascending order by default.
|
|
179
254
|
|
|
180
255
|
```typescript
|
|
181
|
-
//
|
|
256
|
+
// Sort by creation time
|
|
182
257
|
const games = await firestore.query("games", {
|
|
183
258
|
orderBy: "createdAt",
|
|
184
259
|
});
|
|
@@ -186,10 +261,10 @@ const games = await firestore.query("games", {
|
|
|
186
261
|
|
|
187
262
|
### limit
|
|
188
263
|
|
|
189
|
-
|
|
264
|
+
Limits the maximum number of results returned.
|
|
190
265
|
|
|
191
266
|
```typescript
|
|
192
|
-
//
|
|
267
|
+
// Get at most 10 documents
|
|
193
268
|
const games = await firestore.query("games", {
|
|
194
269
|
limit: 10,
|
|
195
270
|
});
|
|
@@ -197,49 +272,204 @@ const games = await firestore.query("games", {
|
|
|
197
272
|
|
|
198
273
|
### offset
|
|
199
274
|
|
|
200
|
-
|
|
275
|
+
Specifies the number of results to skip. Useful for pagination.
|
|
201
276
|
|
|
202
277
|
```typescript
|
|
203
|
-
//
|
|
278
|
+
// Skip the first 20 results and get the next 10
|
|
204
279
|
const games = await firestore.query("games", {
|
|
205
280
|
offset: 20,
|
|
206
281
|
limit: 10,
|
|
207
282
|
});
|
|
208
283
|
```
|
|
209
284
|
|
|
210
|
-
|
|
285
|
+
Example of a compound query:
|
|
211
286
|
|
|
212
287
|
```typescript
|
|
213
|
-
//
|
|
288
|
+
// Get top 10 active games by score
|
|
214
289
|
const topGames = await firestore.query("games", {
|
|
215
290
|
where: [{ field: "active", op: "EQUAL", value: true }],
|
|
216
|
-
orderBy: "score", //
|
|
291
|
+
orderBy: "score", // Sort by score
|
|
217
292
|
limit: 10,
|
|
218
293
|
});
|
|
219
294
|
```
|
|
220
295
|
|
|
221
|
-
##
|
|
296
|
+
## Edge Runtime Examples
|
|
222
297
|
|
|
223
|
-
###
|
|
298
|
+
### Cloudflare Workers
|
|
224
299
|
|
|
225
|
-
|
|
300
|
+
```typescript
|
|
301
|
+
// Set these environment variables in wrangler.toml
|
|
302
|
+
// FIREBASE_PROJECT_ID
|
|
303
|
+
// FIREBASE_PRIVATE_KEY
|
|
304
|
+
// FIREBASE_CLIENT_EMAIL
|
|
226
305
|
|
|
227
|
-
|
|
306
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
307
|
+
|
|
308
|
+
export default {
|
|
309
|
+
async fetch(request, env, ctx) {
|
|
310
|
+
// Load configuration from environment variables
|
|
311
|
+
const firestore = createFirestoreClient({
|
|
312
|
+
projectId: env.FIREBASE_PROJECT_ID,
|
|
313
|
+
privateKey: env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, "\n"),
|
|
314
|
+
clientEmail: env.FIREBASE_CLIENT_EMAIL,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const url = new URL(request.url);
|
|
318
|
+
const path = url.pathname;
|
|
228
319
|
|
|
229
|
-
|
|
320
|
+
// Example API endpoint
|
|
321
|
+
if (path === "/api/games" && request.method === "GET") {
|
|
322
|
+
try {
|
|
323
|
+
// Get active games
|
|
324
|
+
const games = await firestore.query("games", {
|
|
325
|
+
where: [{ field: "active", op: "EQUAL", value: true }],
|
|
326
|
+
limit: 10,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return new Response(JSON.stringify(games), {
|
|
330
|
+
headers: { "Content-Type": "application/json" },
|
|
331
|
+
});
|
|
332
|
+
} catch (error) {
|
|
333
|
+
return new Response(JSON.stringify({ error: error.message }), {
|
|
334
|
+
status: 500,
|
|
335
|
+
headers: { "Content-Type": "application/json" },
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return new Response("Not found", { status: 404 });
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Vercel Edge Functions
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// Set these environment variables in .env.local
|
|
349
|
+
// FIREBASE_PROJECT_ID
|
|
350
|
+
// FIREBASE_PRIVATE_KEY
|
|
351
|
+
// FIREBASE_CLIENT_EMAIL
|
|
352
|
+
|
|
353
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
354
|
+
|
|
355
|
+
export const config = {
|
|
356
|
+
runtime: "edge",
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
export default async function handler(request) {
|
|
360
|
+
// Load configuration from environment variables
|
|
361
|
+
const firestore = createFirestoreClient({
|
|
362
|
+
projectId: process.env.FIREBASE_PROJECT_ID,
|
|
363
|
+
privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, "\n"),
|
|
364
|
+
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
// Get the latest 10 documents
|
|
369
|
+
const documents = await firestore.query("posts", {
|
|
370
|
+
orderBy: "createdAt",
|
|
371
|
+
limit: 10,
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
return new Response(JSON.stringify(documents), {
|
|
375
|
+
headers: { "Content-Type": "application/json" },
|
|
376
|
+
});
|
|
377
|
+
} catch (error) {
|
|
378
|
+
return new Response(JSON.stringify({ error: error.message }), {
|
|
379
|
+
status: 500,
|
|
380
|
+
headers: { "Content-Type": "application/json" },
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Performance Considerations
|
|
387
|
+
|
|
388
|
+
### Token Caching
|
|
389
|
+
|
|
390
|
+
Firebase REST Firestore caches JWT tokens to improve performance. By default, tokens are cached for 50 minutes (actual token expiry is 1 hour). This eliminates the need to generate a new token for each request, improving API request speed.
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
// Tokens are cached internally, so multiple requests
|
|
394
|
+
// have minimal authentication overhead
|
|
395
|
+
const doc1 = await firestore.get("collection", "doc1");
|
|
396
|
+
const doc2 = await firestore.get("collection", "doc2");
|
|
397
|
+
const doc3 = await firestore.get("collection", "doc3");
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Query Optimization
|
|
401
|
+
|
|
402
|
+
When dealing with large amounts of data, consider the following:
|
|
403
|
+
|
|
404
|
+
1. **Set appropriate limits**: Always use the `limit` parameter to restrict the number of documents returned.
|
|
405
|
+
|
|
406
|
+
2. **Query only needed fields**: Future versions will add support for retrieving only specific fields.
|
|
407
|
+
|
|
408
|
+
3. **Create indexes**: For complex queries, create appropriate indexes in the Firebase console.
|
|
409
|
+
|
|
410
|
+
4. **Use pagination**: When retrieving large datasets, implement pagination using `offset` and `limit`.
|
|
411
|
+
|
|
412
|
+
### Edge Environment Considerations
|
|
413
|
+
|
|
414
|
+
In edge environments, be aware of:
|
|
415
|
+
|
|
416
|
+
1. **Cold starts**: Initial execution has token generation overhead.
|
|
417
|
+
|
|
418
|
+
2. **Memory usage**: Be mindful of memory limits when processing large amounts of data.
|
|
419
|
+
|
|
420
|
+
3. **Timeouts**: Long-running queries may hit edge environment timeout limits.
|
|
421
|
+
|
|
422
|
+
## Limitations and Roadmap
|
|
423
|
+
|
|
424
|
+
### Current Limitations
|
|
425
|
+
|
|
426
|
+
- **Batch operations**: The current version does not support batch processing for operating on multiple documents at once.
|
|
427
|
+
- **Transactions**: Atomic transaction operations are not supported.
|
|
428
|
+
- **Real-time listeners**: Due to the nature of REST APIs, real-time data synchronization is not supported.
|
|
429
|
+
- **Subcollections**: The current version has limited direct support for nested subcollections.
|
|
430
|
+
|
|
431
|
+
### Future Roadmap
|
|
432
|
+
|
|
433
|
+
The following features are planned for future versions:
|
|
434
|
+
|
|
435
|
+
- Batch operations support
|
|
436
|
+
- Basic transaction support
|
|
437
|
+
- Improved subcollection support
|
|
438
|
+
- More detailed query options (compound indexes, etc.)
|
|
439
|
+
- Performance optimizations
|
|
440
|
+
|
|
441
|
+
Please report feature requests and bugs via GitHub Issues.
|
|
442
|
+
|
|
443
|
+
## License
|
|
444
|
+
|
|
445
|
+
MIT
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
# Firebase REST Firestore (日本語ドキュメント)
|
|
450
|
+
|
|
451
|
+
Firebase Firestore REST API クライアントは、Cloudflare Workers や Vercel Edge Functions などのエッジランタイム環境向けに設計されています。
|
|
452
|
+
|
|
453
|
+
## 特徴
|
|
454
|
+
|
|
455
|
+
- Firebase Admin SDK が利用できないエッジランタイム環境で動作
|
|
230
456
|
- 完全な CRUD 操作のサポート
|
|
231
457
|
- TypeScript サポート
|
|
232
458
|
- パフォーマンス向上のためのトークンキャッシュ
|
|
233
459
|
- シンプルで直感的な API
|
|
234
460
|
- 環境変数に依存しない明示的な設定
|
|
461
|
+
- Firebase Admin SDK compatible interface (v0.2.0+)
|
|
462
|
+
- Next.js 互換性のための遅延設定検証 (v0.2.1+)
|
|
235
463
|
|
|
236
|
-
|
|
464
|
+
## インストール
|
|
237
465
|
|
|
238
466
|
```bash
|
|
239
467
|
npm install firebase-rest-firestore
|
|
240
468
|
```
|
|
241
469
|
|
|
242
|
-
|
|
470
|
+
## 使い方
|
|
471
|
+
|
|
472
|
+
### 基本的な使い方(明示的な設定)
|
|
243
473
|
|
|
244
474
|
```typescript
|
|
245
475
|
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
@@ -283,26 +513,233 @@ console.log("スコアが50より大きいゲーム:", userGames);
|
|
|
283
513
|
await firestore.delete("games", game.id);
|
|
284
514
|
```
|
|
285
515
|
|
|
286
|
-
|
|
516
|
+
### Firebase Admin SDK 互換インターフェース (v0.2.0+)
|
|
287
517
|
|
|
288
|
-
|
|
518
|
+
バージョン 0.2.0 から、firebase-rest-firestore は Firebase Admin SDK と互換性のあるインターフェースを提供しています:
|
|
289
519
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
- **リアルタイムリスナー**: REST API の性質上、リアルタイムのデータ同期はサポートされていません。
|
|
293
|
-
- **サブコレクション**: 現在のバージョンでは、ネストされたサブコレクションの直接的なサポートは限定的です。
|
|
520
|
+
```typescript
|
|
521
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
294
522
|
|
|
295
|
-
|
|
523
|
+
// 設定を指定してクライアントを作成
|
|
524
|
+
const firestore = createFirestoreClient({
|
|
525
|
+
projectId: "あなたのプロジェクトID",
|
|
526
|
+
privateKey: "サービスアカウントの秘密鍵",
|
|
527
|
+
clientEmail: "サービスアカウントのメールアドレス",
|
|
528
|
+
});
|
|
296
529
|
|
|
297
|
-
|
|
530
|
+
// 自動生成IDでドキュメントを作成
|
|
531
|
+
const gameRef = firestore.collection("games").doc();
|
|
532
|
+
await gameRef.set({
|
|
533
|
+
name: "新しいゲーム",
|
|
534
|
+
createdAt: new Date(),
|
|
535
|
+
score: 100,
|
|
536
|
+
active: true,
|
|
537
|
+
});
|
|
538
|
+
console.log("作成されたゲームID:", gameRef.id);
|
|
298
539
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
540
|
+
// 特定のIDでドキュメントを作成
|
|
541
|
+
await firestore.collection("games").doc("game123").set({
|
|
542
|
+
name: "特定のゲーム",
|
|
543
|
+
createdAt: new Date(),
|
|
544
|
+
});
|
|
304
545
|
|
|
305
|
-
|
|
546
|
+
// ドキュメントの取得
|
|
547
|
+
const gameDoc = await firestore.doc("games/game123").get();
|
|
548
|
+
if (gameDoc.exists) {
|
|
549
|
+
console.log("取得したゲーム:", gameDoc.data());
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// ドキュメントの更新
|
|
553
|
+
await firestore.collection("games").doc("game123").update({
|
|
554
|
+
name: "更新されたゲーム名",
|
|
555
|
+
updatedAt: new Date(),
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// ドキュメントのクエリ
|
|
559
|
+
const querySnapshot = await firestore
|
|
560
|
+
.collection("games")
|
|
561
|
+
.where("score", ">", 50)
|
|
562
|
+
.where("active", "==", true)
|
|
563
|
+
.orderBy("score", "desc")
|
|
564
|
+
.limit(10)
|
|
565
|
+
.get();
|
|
566
|
+
|
|
567
|
+
// クエリ結果の処理
|
|
568
|
+
const games = [];
|
|
569
|
+
querySnapshot.forEach(doc => {
|
|
570
|
+
games.push({
|
|
571
|
+
id: doc.id,
|
|
572
|
+
...doc.data(),
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
console.log("スコアが50より大きいゲーム:", games);
|
|
576
|
+
|
|
577
|
+
// ドキュメントの削除
|
|
578
|
+
await firestore.collection("games").doc("game123").delete();
|
|
579
|
+
|
|
580
|
+
// サブコレクションの操作
|
|
581
|
+
const commentRef = firestore
|
|
582
|
+
.collection("games")
|
|
583
|
+
.doc("game123")
|
|
584
|
+
.collection("comments")
|
|
585
|
+
.doc();
|
|
586
|
+
|
|
587
|
+
await commentRef.set({
|
|
588
|
+
text: "素晴らしいゲーム!",
|
|
589
|
+
createdAt: new Date(),
|
|
590
|
+
});
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
## 設定
|
|
594
|
+
|
|
595
|
+
`FirestoreConfig`オブジェクトには以下のプロパティが必要です:
|
|
596
|
+
|
|
597
|
+
| プロパティ | 説明 |
|
|
598
|
+
| ----------- | ---------------------------------- |
|
|
599
|
+
| projectId | Firebase プロジェクト ID |
|
|
600
|
+
| privateKey | サービスアカウントの秘密鍵 |
|
|
601
|
+
| clientEmail | サービスアカウントのメールアドレス |
|
|
602
|
+
|
|
603
|
+
## API リファレンス
|
|
604
|
+
|
|
605
|
+
### FirestoreClient
|
|
606
|
+
|
|
607
|
+
Firestore と対話するためのメインクラスです。
|
|
608
|
+
|
|
609
|
+
#### create(collectionName, data)
|
|
610
|
+
|
|
611
|
+
指定されたコレクションに新しいドキュメントを作成します。
|
|
612
|
+
|
|
613
|
+
#### get(collectionName, documentId)
|
|
614
|
+
|
|
615
|
+
ID によってドキュメントを取得します。
|
|
616
|
+
|
|
617
|
+
#### update(collectionName, documentId, data)
|
|
618
|
+
|
|
619
|
+
既存のドキュメントを更新します。
|
|
620
|
+
|
|
621
|
+
#### delete(collectionName, documentId)
|
|
622
|
+
|
|
623
|
+
ドキュメントを削除します。
|
|
624
|
+
|
|
625
|
+
#### query(collectionName, options)
|
|
626
|
+
|
|
627
|
+
フィルタリング、並べ替え、ページネーションを使用してコレクション内のドキュメントをクエリします。
|
|
628
|
+
|
|
629
|
+
### createFirestoreClient(config)
|
|
630
|
+
|
|
631
|
+
提供された設定で新しい FirestoreClient インスタンスを作成します。
|
|
632
|
+
|
|
633
|
+
### loadConfigFromEnv()
|
|
634
|
+
|
|
635
|
+
環境変数から設定を読み込むためのヘルパー関数です。
|
|
636
|
+
|
|
637
|
+
## エラーハンドリング
|
|
638
|
+
|
|
639
|
+
Firebase REST Firestore は、API リクエスト中にエラーが発生した場合、適切なエラーメッセージを含む例外をスローします。以下はエラーハンドリングの例です:
|
|
640
|
+
|
|
641
|
+
```typescript
|
|
642
|
+
try {
|
|
643
|
+
// ドキュメントの取得を試みる
|
|
644
|
+
const game = await firestore.get("games", "non-existent-id");
|
|
645
|
+
|
|
646
|
+
// ドキュメントが存在しない場合はnullが返される
|
|
647
|
+
if (game === null) {
|
|
648
|
+
console.log("ドキュメントが見つかりませんでした");
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// ドキュメントが存在する場合の処理
|
|
653
|
+
console.log("取得したゲーム:", game);
|
|
654
|
+
} catch (error) {
|
|
655
|
+
// API呼び出し中のエラー(認証エラーやネットワークエラーなど)
|
|
656
|
+
console.error("Firestoreエラー:", error.message);
|
|
657
|
+
}
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
一般的なエラーケース:
|
|
661
|
+
|
|
662
|
+
- 認証エラー(無効なクレデンシャル)
|
|
663
|
+
- ネットワークエラー
|
|
664
|
+
- 無効なクエリパラメータ
|
|
665
|
+
- Firestore のレート制限
|
|
666
|
+
|
|
667
|
+
## クエリオプションの詳細
|
|
668
|
+
|
|
669
|
+
`query`メソッドでは、以下のオプションを使用して Firestore のドキュメントをフィルタリング、ソート、ページネーションできます:
|
|
670
|
+
|
|
671
|
+
### where
|
|
672
|
+
|
|
673
|
+
複数のフィルター条件を指定できます。各条件は以下のプロパティを持つオブジェクトです:
|
|
674
|
+
|
|
675
|
+
- `field`: フィルタリングするフィールド名
|
|
676
|
+
- `op`: 比較演算子。以下の値が使用可能です:
|
|
677
|
+
- `EQUAL`: 等しい
|
|
678
|
+
- `NOT_EQUAL`: 等しくない
|
|
679
|
+
- `LESS_THAN`: より小さい
|
|
680
|
+
- `LESS_THAN_OR_EQUAL`: 以下
|
|
681
|
+
- `GREATER_THAN`: より大きい
|
|
682
|
+
- `GREATER_THAN_OR_EQUAL`: 以上
|
|
683
|
+
- `ARRAY_CONTAINS`: 配列に含まれる
|
|
684
|
+
- `IN`: 指定した値のいずれかに等しい
|
|
685
|
+
- `ARRAY_CONTAINS_ANY`: 配列が指定した値のいずれかを含む
|
|
686
|
+
- `NOT_IN`: 指定した値のいずれにも等しくない
|
|
687
|
+
- `value`: 比較する値
|
|
688
|
+
|
|
689
|
+
```typescript
|
|
690
|
+
// スコアが50より大きく、activeがtrueのゲームを検索
|
|
691
|
+
const games = await firestore.query("games", {
|
|
692
|
+
where: [
|
|
693
|
+
{ field: "score", op: "GREATER_THAN", value: 50 },
|
|
694
|
+
{ field: "active", op: "EQUAL", value: true },
|
|
695
|
+
],
|
|
696
|
+
});
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### orderBy
|
|
700
|
+
|
|
701
|
+
結果を並べ替えるフィールド名を指定します。デフォルトでは昇順(ASCENDING)でソートされます。
|
|
702
|
+
|
|
703
|
+
```typescript
|
|
704
|
+
// 作成日時で並べ替え
|
|
705
|
+
const games = await firestore.query("games", {
|
|
706
|
+
orderBy: "createdAt",
|
|
707
|
+
});
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
### limit
|
|
711
|
+
|
|
712
|
+
返される結果の最大数を指定します。
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
// 最大10件のドキュメントを取得
|
|
716
|
+
const games = await firestore.query("games", {
|
|
717
|
+
limit: 10,
|
|
718
|
+
});
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### offset
|
|
722
|
+
|
|
723
|
+
結果のスキップ数を指定します。ページネーションに使用できます。
|
|
724
|
+
|
|
725
|
+
```typescript
|
|
726
|
+
// 最初の20件をスキップして、次の10件を取得
|
|
727
|
+
const games = await firestore.query("games", {
|
|
728
|
+
offset: 20,
|
|
729
|
+
limit: 10,
|
|
730
|
+
});
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
複合クエリの例:
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
// アクティブなゲームをスコアの高い順に10件取得
|
|
737
|
+
const topGames = await firestore.query("games", {
|
|
738
|
+
where: [{ field: "active", op: "EQUAL", value: true }],
|
|
739
|
+
orderBy: "score", // スコアでソート
|
|
740
|
+
limit: 10,
|
|
741
|
+
});
|
|
742
|
+
```
|
|
306
743
|
|
|
307
744
|
## エッジランタイムでの使用例
|
|
308
745
|
|
|
@@ -429,3 +866,28 @@ const doc3 = await firestore.get("collection", "doc3");
|
|
|
429
866
|
2. **メモリ使用量**: 大量のデータを一度に処理する場合は、メモリ制限に注意してください。
|
|
430
867
|
|
|
431
868
|
3. **タイムアウト**: 長時間実行されるクエリは、エッジ環境のタイムアウト制限に達する可能性があります。
|
|
869
|
+
|
|
870
|
+
## 制限事項とロードマップ
|
|
871
|
+
|
|
872
|
+
### 現在の制限事項
|
|
873
|
+
|
|
874
|
+
- **バッチ操作**: 現在のバージョンでは、複数のドキュメントを一度に操作するバッチ処理はサポートされていません。
|
|
875
|
+
- **トランザクション**: 原子的なトランザクション操作はサポートされていません。
|
|
876
|
+
- **リアルタイムリスナー**: REST API の性質上、リアルタイムのデータ同期はサポートされていません。
|
|
877
|
+
- **サブコレクション**: 現在のバージョンでは、ネストされたサブコレクションの直接的なサポートは限定的です。
|
|
878
|
+
|
|
879
|
+
### 将来のロードマップ
|
|
880
|
+
|
|
881
|
+
以下の機能は将来のバージョンで実装予定です:
|
|
882
|
+
|
|
883
|
+
- バッチ操作のサポート
|
|
884
|
+
- 基本的なトランザクションのサポート
|
|
885
|
+
- サブコレクションの改善されたサポート
|
|
886
|
+
- より詳細なクエリオプション(複合インデックスなど)
|
|
887
|
+
- パフォーマンス最適化
|
|
888
|
+
|
|
889
|
+
機能リクエストやバグ報告は、GitHub の Issue でお知らせください。
|
|
890
|
+
|
|
891
|
+
## ライセンス
|
|
892
|
+
|
|
893
|
+
MIT
|