@adobe/aio-lib-db 0.1.0-alpha.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/COPYING.txt +7 -0
- package/COPYRIGHT +5 -0
- package/LICENSE +201 -0
- package/README.md +557 -0
- package/index.js +12 -0
- package/lib/AbstractDbCursor.js +350 -0
- package/lib/AggregateCursor.js +187 -0
- package/lib/DbBase.js +149 -0
- package/lib/DbClient.js +114 -0
- package/lib/DbCollection.js +352 -0
- package/lib/DbError.js +21 -0
- package/lib/FindCursor.js +107 -0
- package/lib/api/client.js +96 -0
- package/lib/api/collection.js +425 -0
- package/lib/api/db.js +90 -0
- package/lib/constants.js +44 -0
- package/lib/init.js +35 -0
- package/package.json +56 -0
- package/utils/apiRequest.js +103 -0
- package/utils/axiosUtils.js +57 -0
- package/utils/ejsonHandler.js +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
# aio-lib-db
|
|
2
|
+
|
|
3
|
+
**aio-lib-db** is a powerful document database library for Adobe I/O Runtime applications. It provides structured, queryable, and flexible data persistence with MongoDB-like query capabilities.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Install `aio-lib-db` from npm:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @adobe/aio-lib-db
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or add it to your `package.json`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@adobe/aio-lib-db": "^0.1.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### Setup
|
|
30
|
+
|
|
31
|
+
First, set your credentials in your `.env` file:
|
|
32
|
+
|
|
33
|
+
```env
|
|
34
|
+
__OW_NAMESPACE=your_namespace
|
|
35
|
+
__OW_API_KEY=user:password
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
> To find runtime namespace and credentials, click "Download all" in the Adobe Developer Console for your project workspace and the values will be under `project.workspace.details.runtime.namespaces`.
|
|
39
|
+
|
|
40
|
+
### Basic Usage
|
|
41
|
+
|
|
42
|
+
> When calling `libDb.init()`, you can pass `{ region: '<region>>' }` to specify the region where your database is provisioned.
|
|
43
|
+
> Valid regions are `amer` (default), `emea`, and `apac`.
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
const libDb = require('@adobe/aio-lib-db');
|
|
47
|
+
|
|
48
|
+
async function main() {
|
|
49
|
+
try {
|
|
50
|
+
// Initialize and connect
|
|
51
|
+
const db = await libDb.init({ region: 'amer' });
|
|
52
|
+
const client = await db.connect();
|
|
53
|
+
|
|
54
|
+
// Get a collection
|
|
55
|
+
const users = client.collection('users');
|
|
56
|
+
|
|
57
|
+
// Insert a document
|
|
58
|
+
await users.insertOne({ name: 'John Doe', email: 'john@example.com' });
|
|
59
|
+
|
|
60
|
+
// Find documents
|
|
61
|
+
const cursor = users.find({ name: 'John Doe' });
|
|
62
|
+
const results = await cursor.toArray();
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
// Close any open cursors when the application is done
|
|
66
|
+
await client.close();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Collection Operations
|
|
74
|
+
|
|
75
|
+
### Insert Operations
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// Insert a single document
|
|
79
|
+
const result = await collection.insertOne({
|
|
80
|
+
name: 'Jane Smith',
|
|
81
|
+
email: 'jane@example.com',
|
|
82
|
+
age: 30
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Insert multiple documents
|
|
86
|
+
const result = await collection.insertMany([
|
|
87
|
+
{ name: 'Alice', email: 'alice@example.com' },
|
|
88
|
+
{ name: 'Bob', email: 'bob@example.com' }
|
|
89
|
+
]);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Find Operations
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// Find one document
|
|
96
|
+
const user = await collection.findOne({ email: 'john@example.com' });
|
|
97
|
+
|
|
98
|
+
// Find all documents matching a filter
|
|
99
|
+
const cursor = collection.find({ age: { $gte: 18 } });
|
|
100
|
+
const adults = await cursor.toArray();
|
|
101
|
+
|
|
102
|
+
// Find with projection and sorting
|
|
103
|
+
const cursor = collection.find({ age: { $gte: 18 } })
|
|
104
|
+
.project({ name: 1, email: 1 })
|
|
105
|
+
.sort({ name: 1 })
|
|
106
|
+
.limit(10);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Update Operations
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
// Update one document
|
|
113
|
+
const result = await collection.updateOne(
|
|
114
|
+
{ email: 'john@example.com' },
|
|
115
|
+
{ $set: { age: 31 } }
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Update multiple documents
|
|
119
|
+
const result = await collection.updateMany(
|
|
120
|
+
{ age: { $lt: 18 } },
|
|
121
|
+
{ $set: { category: 'minor' } }
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Find and update
|
|
125
|
+
const updatedUser = await collection.findOneAndUpdate(
|
|
126
|
+
{ email: 'john@example.com' },
|
|
127
|
+
{ $set: { lastLogin: new Date() } },
|
|
128
|
+
{ returnDocument: 'after' }
|
|
129
|
+
);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Delete Operations
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
// Delete one document
|
|
136
|
+
const result = await collection.deleteOne({ email: 'john@example.com' });
|
|
137
|
+
|
|
138
|
+
// Delete multiple documents
|
|
139
|
+
const result = await collection.deleteMany({ age: { $lt: 0 } });
|
|
140
|
+
|
|
141
|
+
// Find and delete
|
|
142
|
+
const deletedUser = await collection.findOneAndDelete({ email: 'john@example.com' });
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Query Building with Cursors
|
|
148
|
+
|
|
149
|
+
> Cursors will close themselves after all results have been processed, but they can be closed early to release resources by calling `cursor.close()`, and best practice is to close them explicitly once they're no longer needed. The `client.close()` method will close all open cursors and connections, so it should be called when the application is shutting down or no longer needs database access.
|
|
150
|
+
|
|
151
|
+
### FindCursor Methods
|
|
152
|
+
|
|
153
|
+
The `find()` method returns a `FindCursor` that supports method chaining:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
const cursor = collection.find({ status: 'active' })
|
|
157
|
+
.filter({ category: 'premium' }) // Additional filtering
|
|
158
|
+
.sort({ createdAt: -1 }) // Sort by creation date (newest first)
|
|
159
|
+
.project({ name: 1, email: 1, _id: 0 }) // Only include name and email
|
|
160
|
+
.limit(20) // Limit to 20 results
|
|
161
|
+
.skip(10) // Skip first 10 results
|
|
162
|
+
.batchSize(5); // Process in batches of 5
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Cursor Iteration
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// Using toArray() - loads all results into memory
|
|
169
|
+
const results = await cursor.toArray();
|
|
170
|
+
|
|
171
|
+
// Using iteration - memory efficient
|
|
172
|
+
while (await cursor.hasNext()) {
|
|
173
|
+
const doc = await cursor.next();
|
|
174
|
+
console.log(doc);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Using for await...of - most convenient
|
|
178
|
+
for await (const doc of cursor) {
|
|
179
|
+
console.log(doc);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Using streams
|
|
183
|
+
const stream = cursor.stream();
|
|
184
|
+
stream.on('data', (doc) => {
|
|
185
|
+
console.log(doc);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Check cursor properties
|
|
189
|
+
console.log('Cursor ID:', cursor.id);
|
|
190
|
+
console.log('Is closed:', cursor.closed);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Cursor Transformations
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
// Transform documents as they're retrieved
|
|
197
|
+
const cursor = collection.find({ status: 'active' })
|
|
198
|
+
.map(doc => ({
|
|
199
|
+
...doc,
|
|
200
|
+
displayName: `${doc.firstName} ${doc.lastName}`,
|
|
201
|
+
isVip: doc.tier === 'premium'
|
|
202
|
+
}));
|
|
203
|
+
|
|
204
|
+
// Chain multiple transformations
|
|
205
|
+
const cursor = collection.find({ status: 'active' })
|
|
206
|
+
.map(doc => ({ ...doc, processed: true }))
|
|
207
|
+
.map(doc => ({ ...doc, timestamp: new Date() }));
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Aggregation Pipeline
|
|
213
|
+
|
|
214
|
+
### Basic Aggregation
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
// Simple aggregation
|
|
218
|
+
const pipeline = [
|
|
219
|
+
{ $match: { status: 'active' } },
|
|
220
|
+
{ $group: { _id: '$category', count: { $sum: 1 } } },
|
|
221
|
+
{ $sort: { count: -1 } }
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
const cursor = collection.aggregate(pipeline);
|
|
225
|
+
const results = await cursor.toArray();
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Chained Aggregation Building
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// Build aggregation pipeline using method chaining
|
|
232
|
+
const cursor = collection.aggregate()
|
|
233
|
+
.match({ status: 'active' })
|
|
234
|
+
.group({ _id: '$category', total: { $sum: '$amount' } })
|
|
235
|
+
.sort({ total: -1 })
|
|
236
|
+
.limit(10)
|
|
237
|
+
.project({ category: '$_id', total: 1, _id: 0 });
|
|
238
|
+
|
|
239
|
+
const topCategories = await cursor.toArray();
|
|
240
|
+
|
|
241
|
+
// Geospatial aggregation example
|
|
242
|
+
const nearbyStores = await collection.aggregate()
|
|
243
|
+
.geoNear({
|
|
244
|
+
near: { type: 'Point', coordinates: [-122.4194, 37.7749] }, // San Francisco
|
|
245
|
+
distanceField: 'distance',
|
|
246
|
+
maxDistance: 1000, // 1km radius
|
|
247
|
+
spherical: true
|
|
248
|
+
})
|
|
249
|
+
.match({ status: 'open' })
|
|
250
|
+
.limit(10)
|
|
251
|
+
.toArray();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Advanced Aggregation
|
|
255
|
+
|
|
256
|
+
```javascript
|
|
257
|
+
// Complex aggregation with multiple stages
|
|
258
|
+
const cursor = collection.aggregate()
|
|
259
|
+
.match({ dateCreated: { $gte: new Date('2024-01-01') } })
|
|
260
|
+
.lookup({
|
|
261
|
+
from: 'categories',
|
|
262
|
+
localField: 'categoryId',
|
|
263
|
+
foreignField: '_id',
|
|
264
|
+
as: 'category'
|
|
265
|
+
})
|
|
266
|
+
.unwind('$category')
|
|
267
|
+
.redact({
|
|
268
|
+
$cond: {
|
|
269
|
+
if: { $eq: ['$category.status', 'active'] },
|
|
270
|
+
then: '$$DESCEND',
|
|
271
|
+
else: '$$PRUNE'
|
|
272
|
+
}
|
|
273
|
+
})
|
|
274
|
+
.group({
|
|
275
|
+
_id: '$category.name',
|
|
276
|
+
totalSales: { $sum: '$amount' },
|
|
277
|
+
averageOrder: { $avg: '$amount' },
|
|
278
|
+
orderCount: { $sum: 1 }
|
|
279
|
+
})
|
|
280
|
+
.sort({ totalSales: -1 })
|
|
281
|
+
.limit(5)
|
|
282
|
+
.out('sales_summary'); // Output results to a new collection
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Advanced Features
|
|
288
|
+
|
|
289
|
+
### Indexing
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
// Create indexes for better query performance
|
|
293
|
+
await collection.createIndex({ email: 1 }, { unique: true });
|
|
294
|
+
await collection.createIndex({ 'profile.age': 1, status: 1 });
|
|
295
|
+
|
|
296
|
+
// List all indexes
|
|
297
|
+
const indexes = await collection.getIndexes();
|
|
298
|
+
|
|
299
|
+
// Drop an index
|
|
300
|
+
await collection.dropIndex('email_1');
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Counting Documents
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
// Fast count estimate (uses collection metadata)
|
|
307
|
+
const estimate = await collection.estimatedDocumentCount();
|
|
308
|
+
|
|
309
|
+
// Accurate count with filter (scans documents)
|
|
310
|
+
const activeUsers = await collection.countDocuments({ status: 'active' });
|
|
311
|
+
|
|
312
|
+
// Count all documents accurately
|
|
313
|
+
const totalExact = await collection.countDocuments({});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Bulk Operations
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
// Perform multiple operations in a single request
|
|
320
|
+
const operations = [
|
|
321
|
+
{ insertOne: { document: { name: 'Alice' } } },
|
|
322
|
+
{ updateOne: { filter: { name: 'Bob' }, update: { $set: { age: 30 } } } },
|
|
323
|
+
{ deleteOne: { filter: { name: 'Charlie' } } }
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
const result = await collection.bulkWrite(operations);
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Collection Management
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
// Drop a collection (permanently delete)
|
|
333
|
+
await collection.drop();
|
|
334
|
+
|
|
335
|
+
// Rename a collection
|
|
336
|
+
await collection.renameCollection('new_collection_name');
|
|
337
|
+
|
|
338
|
+
// Create a new collection with options
|
|
339
|
+
const newCollection = await client.createCollection('analytics', {
|
|
340
|
+
validator: {
|
|
341
|
+
$jsonSchema: {
|
|
342
|
+
required: ['userId', 'action', 'timestamp'],
|
|
343
|
+
properties: {
|
|
344
|
+
userId: { type: 'string' },
|
|
345
|
+
action: { type: 'string' },
|
|
346
|
+
timestamp: { type: 'date' }
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Query Options
|
|
354
|
+
|
|
355
|
+
```javascript
|
|
356
|
+
// Advanced query options
|
|
357
|
+
const cursor = collection.find({ status: 'active' })
|
|
358
|
+
.hint({ status: 1 }) // Use specific index
|
|
359
|
+
.maxTimeMS(5000) // Set query timeout
|
|
360
|
+
.readConcern({ level: 'majority' }) // Set read concern
|
|
361
|
+
.collation({ locale: 'en', strength: 2 }) // Case-insensitive sorting
|
|
362
|
+
.noCursorTimeout(true); // Disable cursor timeout
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Error Handling
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
const { DbError } = require('@adobe/aio-lib-db');
|
|
371
|
+
|
|
372
|
+
try {
|
|
373
|
+
await collection.insertOne({ email: 'invalid-email' });
|
|
374
|
+
} catch (error) {
|
|
375
|
+
if (error instanceof DbError) {
|
|
376
|
+
console.error('Database error:', error.message);
|
|
377
|
+
} else {
|
|
378
|
+
console.error('Unexpected error:', error);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Best Practices
|
|
386
|
+
|
|
387
|
+
### 1. **Always Close Connections**
|
|
388
|
+
|
|
389
|
+
```javascript
|
|
390
|
+
const client = await db.connect();
|
|
391
|
+
try {
|
|
392
|
+
// Your database operations
|
|
393
|
+
} finally {
|
|
394
|
+
await client.close();
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 2. **Use Projections for Large Documents**
|
|
399
|
+
|
|
400
|
+
```javascript
|
|
401
|
+
// Only fetch needed fields
|
|
402
|
+
const users = await collection.find({})
|
|
403
|
+
.project({ name: 1, email: 1, _id: 0 })
|
|
404
|
+
.toArray();
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 3. **Use Indexes for Frequent Queries**
|
|
408
|
+
|
|
409
|
+
```javascript
|
|
410
|
+
// Create indexes for frequently queried fields
|
|
411
|
+
await collection.createIndex({ email: 1 });
|
|
412
|
+
await collection.createIndex({ status: 1, createdAt: -1 });
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### 4. **Handle Large Result Sets with Cursors**
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
// For large datasets, use cursor iteration instead of toArray()
|
|
419
|
+
for await (const doc of collection.find({})) {
|
|
420
|
+
// Process one document at a time
|
|
421
|
+
await processDocument(doc);
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### 5. **Use Aggregation for Complex Queries**
|
|
426
|
+
|
|
427
|
+
```javascript
|
|
428
|
+
// Use aggregation for complex data processing
|
|
429
|
+
const report = await collection.aggregate()
|
|
430
|
+
.match({ date: { $gte: startDate } })
|
|
431
|
+
.group({ _id: '$category', total: { $sum: '$amount' } })
|
|
432
|
+
.sort({ total: -1 })
|
|
433
|
+
.toArray();
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## API Reference
|
|
439
|
+
|
|
440
|
+
### DbClient
|
|
441
|
+
|
|
442
|
+
- `dbStats()` - Get database statistics
|
|
443
|
+
- `listCollections(filter?, options?)` - List collections
|
|
444
|
+
- `collection(name)` - Get collection instance
|
|
445
|
+
- `createCollection(name, options?)` - Create new collection
|
|
446
|
+
- `close()` - Close the connection and all open cursors
|
|
447
|
+
|
|
448
|
+
### DbCollection
|
|
449
|
+
|
|
450
|
+
**Insert Operations:**
|
|
451
|
+
- `insertOne(document, options?)` - Insert single document
|
|
452
|
+
- `insertMany(documents, options?)` - Insert multiple documents
|
|
453
|
+
|
|
454
|
+
**Find Operations:**
|
|
455
|
+
- `findOne(filter, options?)` - Find single document
|
|
456
|
+
- `find(filter?, options?)` - Find multiple documents (returns FindCursor)
|
|
457
|
+
- `findArray(filter?, options?)` - Find single batch as array
|
|
458
|
+
|
|
459
|
+
**Update Operations:**
|
|
460
|
+
- `updateOne(filter, update, options?)` - Update single document
|
|
461
|
+
- `updateMany(filter, update, options?)` - Update multiple documents
|
|
462
|
+
- `findOneAndUpdate(filter, update, options?)` - Find and update
|
|
463
|
+
- `replaceOne(filter, replacement, options?)` - Replace document
|
|
464
|
+
|
|
465
|
+
**Delete Operations:**
|
|
466
|
+
- `deleteOne(filter, options?)` - Delete single document
|
|
467
|
+
- `deleteMany(filter, options?)` - Delete multiple documents
|
|
468
|
+
- `findOneAndDelete(filter, options?)` - Find and delete
|
|
469
|
+
|
|
470
|
+
**Aggregation:**
|
|
471
|
+
- `aggregate(pipeline?, options?)` - Run aggregation (returns AggregateCursor)
|
|
472
|
+
|
|
473
|
+
**Utility Operations:**
|
|
474
|
+
- `countDocuments(filter?, options?)` - Count documents
|
|
475
|
+
- `estimatedDocumentCount(options?)` - Estimate document count from metadata
|
|
476
|
+
- `distinct(field, filter?, options?)` - Get distinct values
|
|
477
|
+
- `bulkWrite(operations, options?)` - Bulk operations
|
|
478
|
+
|
|
479
|
+
**Statistics & Monitoring:**
|
|
480
|
+
- `stats(options?)` - Get collection statistics
|
|
481
|
+
|
|
482
|
+
**Index Operations:**
|
|
483
|
+
- `createIndex(specification, options?)` - Create index
|
|
484
|
+
- `getIndexes()` - List indexes
|
|
485
|
+
- `dropIndex(indexName, options?)` - Drop index
|
|
486
|
+
|
|
487
|
+
**Collection Management:**
|
|
488
|
+
- `drop(options?)` - Drop the collection
|
|
489
|
+
- `renameCollection(newName, options?)` - Rename collection
|
|
490
|
+
|
|
491
|
+
### FindCursor
|
|
492
|
+
|
|
493
|
+
**Query Building:**
|
|
494
|
+
- `filter(filter)` - Set query filter
|
|
495
|
+
- `sort(sort, direction?)` - Set sort order
|
|
496
|
+
- `project(projection)` - Set field projection
|
|
497
|
+
- `limit(limit)` - Set result limit
|
|
498
|
+
- `skip(skip)` - Set number to skip
|
|
499
|
+
- `batchSize(size)` - Set batch size
|
|
500
|
+
|
|
501
|
+
**Iteration:**
|
|
502
|
+
- `hasNext()` - Check if more results available
|
|
503
|
+
- `next()` - Get next document
|
|
504
|
+
- `toArray()` - Get all results as array
|
|
505
|
+
|
|
506
|
+
**Properties:**
|
|
507
|
+
- `id` - Get cursor ID
|
|
508
|
+
- `closed` - Check if cursor is closed and exhausted
|
|
509
|
+
|
|
510
|
+
**Utilities:**
|
|
511
|
+
- `map(transform)` - Transform documents
|
|
512
|
+
- `stream(transform?)` - Get readable stream
|
|
513
|
+
- `close()` - Close the cursor and release resources
|
|
514
|
+
|
|
515
|
+
### AggregateCursor
|
|
516
|
+
|
|
517
|
+
**Pipeline Building:**
|
|
518
|
+
- `match(filter)` - Add $match stage
|
|
519
|
+
- `group(groupSpec)` - Add $group stage
|
|
520
|
+
- `sort(sort)` - Add $sort stage
|
|
521
|
+
- `project(projection)` - Add $project stage
|
|
522
|
+
- `limit(limit)` - Add $limit stage
|
|
523
|
+
- `skip(skip)` - Add $skip stage
|
|
524
|
+
- `lookup(lookupSpec)` - Add $lookup stage
|
|
525
|
+
- `unwind(path)` - Add $unwind stage
|
|
526
|
+
- `out(outSpec)` - Add $out stage (output to collection)
|
|
527
|
+
- `redact(redactSpec)` - Add $redact stage (conditional filtering)
|
|
528
|
+
- `geoNear(geoNearSpec)` - Add $geoNear stage (geospatial queries)
|
|
529
|
+
- `addStage(stage)` - Add custom stage
|
|
530
|
+
|
|
531
|
+
**Iteration:** (Same as FindCursor)
|
|
532
|
+
- `hasNext()`, `next()`, `toArray()`, `stream()`, etc.
|
|
533
|
+
|
|
534
|
+
**Properties:**
|
|
535
|
+
- `id` - Get cursor ID
|
|
536
|
+
- `closed` - Check if cursor is closed and exhausted
|
|
537
|
+
|
|
538
|
+
**Utilities:**
|
|
539
|
+
- `close()` - Close the cursor and release resources
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## Why Use aio-lib-db?
|
|
544
|
+
|
|
545
|
+
- **MongoDB-like Syntax**: Familiar query language and operations
|
|
546
|
+
- **Powerful Querying**: Complex filtering, sorting, and aggregation
|
|
547
|
+
- **Cursor Support**: Memory-efficient iteration over large datasets
|
|
548
|
+
- **Method Chaining**: Fluent API for building complex queries
|
|
549
|
+
- **Type Safety**: Comprehensive input validation and error handling
|
|
550
|
+
- **Streaming Support**: Process large datasets without memory issues
|
|
551
|
+
- **Native Integration**: Built specifically for Adobe I/O Runtime
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Support
|
|
556
|
+
|
|
557
|
+
For issues, feature requests, or questions, please refer to the project's issue tracker or documentation.
|
package/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
module.exports = require('./lib/init')
|