0
# Collection Operations
1
2
Document storage and retrieval with powerful querying, indexing, and aggregation capabilities. Collections are the primary containers for documents in LokiJS.
3
4
## Capabilities
5
6
### Collection Constructor
7
8
Creates a new collection with optional configuration for indexing and behavior.
9
10
```javascript { .api }
11
/**
12
* Creates a new collection
13
* @param name - Collection name
14
* @param options - Collection configuration options
15
*/
16
constructor Collection(name: string, options?: CollectionOptions);
17
18
interface CollectionOptions {
19
/** Array of field names that should be unique */
20
unique?: string[];
21
/** Array of field names for exact matching indexes */
22
exact?: string[];
23
/** Array of field names to create binary indexes on */
24
indices?: string[];
25
/** Enable adaptive binary indices */
26
adaptiveBinaryIndices?: boolean;
27
/** Enable async listeners */
28
asyncListeners?: boolean;
29
/** Disable meta properties ($loki, meta) */
30
disableMeta?: boolean;
31
/** Disable changes API tracking */
32
disableChangesApi?: boolean;
33
/** Disable delta changes API */
34
disableDeltaChangesApi?: boolean;
35
/** Enable auto-update for live objects */
36
autoupdate?: boolean;
37
/** Clone objects when retrieving */
38
clone?: boolean;
39
/** Clone method ('parse-stringify', 'jquery-extend-deep', 'shallow', 'shallow-assign') */
40
cloneMethod?: string;
41
/** Enable transactional mode */
42
transactional?: boolean;
43
/** Time to live in milliseconds */
44
ttl?: number;
45
/** TTL interval check in milliseconds */
46
ttlInterval?: number;
47
}
48
```
49
50
### Basic CRUD Operations
51
52
Fundamental create, read, update, and delete operations for documents.
53
54
```javascript { .api }
55
/**
56
* Insert one or more documents into the collection
57
* @param doc - Document or array of documents to insert
58
* @returns Inserted document(s) with generated $loki id
59
*/
60
insert(doc: object | object[]): object | object[];
61
62
/**
63
* Update an existing document
64
* @param doc - Document to update (must have $loki id)
65
* @returns Updated document
66
*/
67
update(doc: object): object;
68
69
/**
70
* Remove a document from the collection
71
* @param doc - Document to remove (must have $loki id)
72
* @returns Removed document
73
*/
74
remove(doc: object): object;
75
76
/**
77
* Remove multiple documents in batch
78
* @param batch - Array of documents to remove
79
*/
80
removeBatch(batch: object[]): void;
81
82
/**
83
* Remove all documents matching query
84
* @param query - Query object to match documents for removal
85
*/
86
removeWhere(query: object): void;
87
88
/**
89
* Clear all documents from collection
90
* @param options - Clear options
91
*/
92
clear(options?: object): void;
93
```
94
95
**Usage Examples:**
96
97
```javascript
98
const users = db.addCollection('users');
99
100
// Insert single document
101
const user = users.insert({ name: 'Alice', age: 25, email: 'alice@example.com' });
102
console.log(user.$loki); // Auto-generated ID
103
104
// Insert multiple documents
105
const newUsers = users.insert([
106
{ name: 'Bob', age: 30, email: 'bob@example.com' },
107
{ name: 'Charlie', age: 35, email: 'charlie@example.com' }
108
]);
109
110
// Update document
111
user.age = 26;
112
users.update(user);
113
114
// Remove document
115
users.remove(user);
116
117
// Remove documents matching criteria
118
users.removeWhere({ age: { $lt: 30 } });
119
120
// Clear all documents
121
users.clear();
122
```
123
124
### Querying Operations
125
126
Find and retrieve documents using various query methods.
127
128
```javascript { .api }
129
/**
130
* Find documents matching query criteria
131
* @param query - Query object (empty object or undefined returns all)
132
* @returns Array of matching documents
133
*/
134
find(query?: object): object[];
135
136
/**
137
* Find first document matching query criteria
138
* @param query - Query object
139
* @returns First matching document or null
140
*/
141
findOne(query?: object): object | null;
142
143
/**
144
* Get document by $loki id
145
* @param id - Document $loki id
146
* @param returnPosition - If true, return array index instead of document
147
* @returns Document or index, or null if not found
148
*/
149
get(id: number, returnPosition?: boolean): object | number | null;
150
151
/**
152
* Find document by indexed field value (fastest lookup)
153
* @param field - Indexed field name
154
* @param value - Field value to search for
155
* @returns First matching document or null
156
*/
157
by(field: string, value: any): object | null;
158
159
/**
160
* Filter documents using a custom function
161
* @param fun - Filter function returning boolean
162
* @returns Array of documents where function returns true
163
*/
164
where(fun: (obj: object) => boolean): object[];
165
```
166
167
**Usage Examples:**
168
169
```javascript
170
// Find all active users
171
const activeUsers = users.find({ active: true });
172
173
// Find users over 25
174
const matureUsers = users.find({ age: { $gt: 25 } });
175
176
// Find first user named 'Alice'
177
const alice = users.findOne({ name: 'Alice' });
178
179
// Get document by ID
180
const user = users.get(5);
181
182
// Find by indexed field
183
const user = users.by('email', 'alice@example.com');
184
185
// Custom filter function
186
const youngActiveUsers = users.where(obj => obj.age < 30 && obj.active);
187
```
188
189
### Advanced Finding
190
191
Advanced search capabilities including templates and compound operations.
192
193
```javascript { .api }
194
/**
195
* Find documents matching template object
196
* @param template - Template object to match against
197
* @returns Array of matching documents
198
*/
199
byExample(template: object): object[];
200
201
/**
202
* Find single object matching template
203
* @param template - Template object to match against
204
* @returns First matching document or null
205
*/
206
findObject(template: object): object | null;
207
208
/**
209
* Find multiple objects matching template
210
* @param template - Template object to match against
211
* @returns Array of matching documents
212
*/
213
findObjects(template: object): object[];
214
215
/**
216
* Find documents and update them in one operation
217
* @param filterObject - Query to find documents
218
* @param updateFunction - Function to update each document
219
* @returns Array of updated documents
220
*/
221
findAndUpdate(filterObject: object, updateFunction: (obj: object) => void): object[];
222
223
/**
224
* Find documents and remove them in one operation
225
* @param filterObject - Query to find documents
226
* @returns Array of removed documents
227
*/
228
findAndRemove(filterObject: object): object[];
229
230
/**
231
* Update documents matching filter function
232
* @param filterFunction - Function to identify documents to update
233
* @param updateFunction - Function to update each document
234
*/
235
updateWhere(filterFunction: (obj: object) => boolean, updateFunction: (obj: object) => void): void;
236
```
237
238
**Usage Examples:**
239
240
```javascript
241
// Find by example template
242
const users = users.byExample({ active: true, department: 'Engineering' });
243
244
// Find and update in one operation
245
const updated = users.findAndUpdate(
246
{ active: false },
247
(obj) => { obj.lastLogin = new Date(); }
248
);
249
250
// Find and remove inactive users
251
const removed = users.findAndRemove({ active: false });
252
253
// Update where function matches
254
users.updateWhere(
255
obj => obj.age > 65,
256
obj => { obj.retired = true; }
257
);
258
```
259
260
### Counting and Statistics
261
262
Count documents and calculate statistical values across the collection.
263
264
```javascript { .api }
265
/**
266
* Count documents in collection
267
* @param query - Optional query to filter documents
268
* @returns Number of matching documents
269
*/
270
count(query?: object): number;
271
272
/**
273
* Get maximum value of a field
274
* @param field - Field name to find maximum value
275
* @returns Maximum value
276
*/
277
max(field: string): any;
278
279
/**
280
* Get minimum value of a field
281
* @param field - Field name to find minimum value
282
* @returns Minimum value
283
*/
284
min(field: string): any;
285
286
/**
287
* Get record with maximum field value
288
* @param field - Field name to compare
289
* @returns Document with maximum field value
290
*/
291
maxRecord(field: string): object;
292
293
/**
294
* Get record with minimum field value
295
* @param field - Field name to compare
296
* @returns Document with minimum field value
297
*/
298
minRecord(field: string): object;
299
300
/**
301
* Calculate average of field values
302
* @param field - Field name to average
303
* @returns Average value
304
*/
305
avg(field: string): number;
306
307
/**
308
* Calculate standard deviation of field values
309
* @param field - Field name to calculate standard deviation
310
* @returns Standard deviation
311
*/
312
stdDev(field: string): number;
313
314
/**
315
* Find most frequent value in field
316
* @param field - Field name to analyze
317
* @returns Most frequent value
318
*/
319
mode(field: string): any;
320
321
/**
322
* Calculate median value of field
323
* @param field - Field name to calculate median
324
* @returns Median value
325
*/
326
median(field: string): number;
327
```
328
329
**Usage Examples:**
330
331
```javascript
332
// Count all users
333
const totalUsers = users.count();
334
335
// Count active users
336
const activeCount = users.count({ active: true });
337
338
// Statistical operations
339
const maxAge = users.max('age');
340
const minAge = users.min('age');
341
const avgAge = users.avg('age');
342
const oldestUser = users.maxRecord('age');
343
344
// Distribution analysis
345
const commonDepartment = users.mode('department');
346
const medianSalary = users.median('salary');
347
```
348
349
### Indexing Operations
350
351
Manage indexes for improved query performance.
352
353
```javascript { .api }
354
/**
355
* Ensure binary index exists on property
356
* @param property - Property name to index
357
* @param force - Force index rebuild
358
*/
359
ensureIndex(property: string, force?: boolean): void;
360
361
/**
362
* Ensure unique index exists on field
363
* @param field - Field name for unique index
364
*/
365
ensureUniqueIndex(field: string): void;
366
367
/**
368
* Ensure all configured indexes exist
369
* @param force - Force rebuild of all indexes
370
*/
371
ensureAllIndexes(force?: boolean): void;
372
373
/**
374
* Check and optionally rebuild specific index
375
* @param property - Property name to check
376
* @param options - Check options
377
*/
378
checkIndex(property: string, options?: object): void;
379
380
/**
381
* Check and optionally rebuild all indexes
382
* @param options - Check options
383
*/
384
checkAllIndexes(options?: object): void;
385
386
/**
387
* Get values from binary index
388
* @param property - Indexed property name
389
* @returns Array of indexed values
390
*/
391
getBinaryIndexValues(property: string): any[];
392
```
393
394
**Usage Examples:**
395
396
```javascript
397
// Create collection with indexes
398
const users = db.addCollection('users', {
399
unique: ['email'],
400
indices: ['age', 'department']
401
});
402
403
// Add index later
404
users.ensureIndex('lastName');
405
406
// Check if indexes need rebuilding
407
users.checkAllIndexes();
408
409
// Get indexed values
410
const departments = users.getBinaryIndexValues('department');
411
```
412
413
### Transform Operations
414
415
Manage named transform pipelines for reusable query operations.
416
417
```javascript { .api }
418
/**
419
* Add a named transform to the collection
420
* @param name - Transform name
421
* @param transform - Array of transform steps
422
*/
423
addTransform(name: string, transform: any[]): void;
424
425
/**
426
* Get a named transform by name
427
* @param name - Transform name
428
* @returns Transform array or null if not found
429
*/
430
getTransform(name: string): any[] | null;
431
432
/**
433
* Update an existing named transform
434
* @param name - Transform name
435
* @param transform - New transform steps
436
*/
437
setTransform(name: string, transform: any[]): void;
438
439
/**
440
* Remove a named transform
441
* @param name - Transform name
442
*/
443
removeTransform(name: string): void;
444
```
445
446
**Usage Examples:**
447
448
```javascript
449
// Define a reusable transform
450
users.addTransform('activeUsers', [
451
{ type: 'find', value: { active: true } },
452
{ type: 'simplesort', property: 'name' }
453
]);
454
455
// Use the transform
456
const result = users.chain('activeUsers').data();
457
458
// Update transform
459
users.setTransform('activeUsers', [
460
{ type: 'find', value: { active: true, verified: true } },
461
{ type: 'simplesort', property: 'name' }
462
]);
463
464
// Remove transform
465
users.removeTransform('activeUsers');
466
```
467
468
### Transaction Support
469
470
Transactional operations for consistent data modifications.
471
472
```javascript { .api }
473
/**
474
* Start a transaction on the collection
475
* @returns Collection instance for chaining
476
*/
477
startTransaction(): Collection;
478
479
/**
480
* Commit the current transaction
481
* @returns Collection instance for chaining
482
*/
483
commit(): Collection;
484
485
/**
486
* Rollback the current transaction
487
* @returns Collection instance for chaining
488
*/
489
rollback(): Collection;
490
```
491
492
**Usage Examples:**
493
494
```javascript
495
// Start transaction
496
users.startTransaction();
497
498
try {
499
// Perform multiple operations
500
users.insert({ name: 'Alice', age: 25 });
501
users.insert({ name: 'Bob', age: 30 });
502
503
// Update existing records
504
const activeUsers = users.find({ active: true });
505
activeUsers.forEach(user => {
506
user.lastUpdated = new Date();
507
users.update(user);
508
});
509
510
// Commit changes
511
users.commit();
512
console.log('Transaction committed successfully');
513
} catch (error) {
514
// Rollback on error
515
users.rollback();
516
console.error('Transaction rolled back:', error);
517
}
518
```
519
520
### TTL (Time To Live) Configuration
521
522
Configure automatic document expiration based on age.
523
524
```javascript { .api }
525
/**
526
* Set TTL (Time To Live) for documents in collection
527
* @param age - Maximum age in milliseconds
528
* @param interval - Check interval in milliseconds
529
*/
530
setTTL(age: number, interval?: number): void;
531
```
532
533
**Usage Examples:**
534
535
```javascript
536
// Set TTL when creating collection
537
const sessions = db.addCollection('sessions', {
538
ttl: 24 * 60 * 60 * 1000, // 24 hours
539
ttlInterval: 60 * 1000 // Check every minute
540
});
541
542
// Or set TTL later
543
sessions.setTTL(
544
30 * 60 * 1000, // 30 minutes
545
5 * 60 * 1000 // Check every 5 minutes
546
);
547
548
// Documents will be automatically removed when they exceed the age limit
549
```
550
551
### Auto-Update Observers
552
553
Manage automatic updates for live objects.
554
555
```javascript { .api }
556
/**
557
* Add auto-update observer for an object
558
* @param object - Object to observe for changes
559
*/
560
addAutoUpdateObserver(object: object): void;
561
562
/**
563
* Remove auto-update observer for an object
564
* @param object - Object to stop observing
565
*/
566
removeAutoUpdateObserver(object: object): void;
567
```
568
569
**Usage Examples:**
570
571
```javascript
572
// Enable auto-update for collection
573
const users = db.addCollection('users', {
574
autoupdate: true
575
});
576
577
// Insert document
578
const user = users.insert({ name: 'Alice', age: 25 });
579
580
// Modify the object directly - changes will be automatically saved
581
user.age = 26; // Collection automatically updated
582
583
// Manually manage observers
584
users.addAutoUpdateObserver(user);
585
users.removeAutoUpdateObserver(user);
586
```
587
588
### Staging Operations
589
590
Stage and commit changes in batches.
591
592
```javascript { .api }
593
/**
594
* Stage an object for later commit
595
* @param stageName - Name of the stage
596
* @param obj - Object to stage
597
*/
598
stage(stageName: string, obj: object): void;
599
600
/**
601
* Get staged objects by stage name
602
* @param name - Stage name
603
* @returns Array of staged objects
604
*/
605
getStage(name: string): object[];
606
607
/**
608
* Commit staged changes
609
* @param stageName - Name of stage to commit
610
* @param message - Optional commit message
611
*/
612
commitStage(stageName: string, message?: string): void;
613
```
614
615
**Usage Examples:**
616
617
```javascript
618
// Stage multiple changes
619
users.stage('batch1', { name: 'Alice', age: 25 });
620
users.stage('batch1', { name: 'Bob', age: 30 });
621
users.stage('batch1', { name: 'Charlie', age: 35 });
622
623
// Review staged changes
624
const staged = users.getStage('batch1');
625
console.log('Staged documents:', staged.length);
626
627
// Commit the stage
628
users.commitStage('batch1', 'Added new users batch');
629
```
630
631
### Advanced Operations
632
633
Specialized operations for complex data manipulation and analysis.
634
635
```javascript { .api }
636
/**
637
* Create a chainable resultset for complex operations
638
* @param transform - Transform name to apply
639
* @param parameters - Transform parameters
640
* @returns Resultset for chaining operations
641
*/
642
chain(transform?: string, parameters?: object): Resultset;
643
644
/**
645
* Extract unique values from a field
646
* @param field - Field name to extract values from
647
* @returns Array of unique values
648
*/
649
extract(field: string): any[];
650
651
/**
652
* Perform map-reduce operation on collection
653
* @param mapFunction - Map function to apply to each document
654
* @param reduceFunction - Reduce function to combine results
655
* @returns Reduced result
656
*/
657
mapReduce(mapFunction: (obj: object) => any, reduceFunction: (array: any[]) => any): any;
658
659
/**
660
* Perform equi-join with external data
661
* @param joinData - External data to join with
662
* @param leftJoinProp - Property from collection documents
663
* @param rightJoinProp - Property from external data
664
* @param mapFun - Optional function to transform join results
665
* @param dataOptions - Additional options
666
* @returns Array of joined results
667
*/
668
eqJoin(joinData: any[], leftJoinProp: string, rightJoinProp: string, mapFun?: Function, dataOptions?: object): object[];
669
```
670
671
**Usage Examples:**
672
673
```javascript
674
// Chain complex operations
675
const result = users.chain()
676
.find({ active: true })
677
.where(obj => obj.age > 25)
678
.simplesort('name')
679
.limit(10)
680
.data();
681
682
// Extract unique departments
683
const departments = users.extract('department');
684
685
// Map-reduce to calculate department sizes
686
const deptSizes = users.mapReduce(
687
obj => ({ [obj.department]: 1 }),
688
results => {
689
const counts = {};
690
results.forEach(result => {
691
Object.keys(result).forEach(dept => {
692
counts[dept] = (counts[dept] || 0) + result[dept];
693
});
694
});
695
return counts;
696
}
697
);
698
699
// Join with external data
700
const orders = [
701
{ userId: 1, total: 100 },
702
{ userId: 2, total: 200 }
703
];
704
const usersWithOrders = users.eqJoin(orders, 'id', 'userId');
705
```
706
707
### Async Operations
708
709
Perform asynchronous operations on collections.
710
711
```javascript { .api }
712
/**
713
* Execute function asynchronously on collection
714
* @param fun - Function to execute
715
* @param callback - Completion callback
716
*/
717
async(fun: Function, callback: Function): void;
718
```
719
720
**Usage Examples:**
721
722
```javascript
723
// Async operation example
724
users.async(
725
function(collection) {
726
// Perform heavy operation
727
return collection.find({ department: 'Engineering' })
728
.map(user => ({ ...user, processed: true }));
729
},
730
function(result) {
731
console.log('Async operation completed:', result.length);
732
}
733
);
734
```
735
736
### Internal Methods
737
738
Low-level methods for advanced usage and debugging.
739
740
```javascript { .api }
741
/**
742
* Ensure collection has sequential IDs without gaps
743
*/
744
ensureId(): void;
745
746
/**
747
* Asynchronous version of ensureId
748
* @param callback - Completion callback
749
*/
750
ensureIdAsync(callback: Function): void;
751
752
/**
753
* Configure collection options after creation
754
* @param options - Configuration options
755
*/
756
configureOptions(options: CollectionOptions): void;
757
758
/**
759
* Get binary index position for a data position
760
* @param dataPosition - Position in data array
761
* @param binaryIndexName - Name of binary index
762
* @returns Index position
763
*/
764
getBinaryIndexPosition(dataPosition: number, binaryIndexName: string): number;
765
766
/**
767
* Calculate range start for binary index searches
768
* @param prop - Property name
769
* @param val - Search value
770
* @param adaptive - Whether to use adaptive indices
771
* @param usingDotNotation - Whether using dot notation
772
* @returns Range start position
773
*/
774
calculateRangeStart(prop: string, val: any, adaptive?: boolean, usingDotNotation?: boolean): number;
775
776
/**
777
* Calculate range end for binary index searches
778
* @param prop - Property name
779
* @param val - Search value
780
* @param usingDotNotation - Whether using dot notation
781
* @returns Range end position
782
*/
783
calculateRangeEnd(prop: string, val: any, usingDotNotation?: boolean): number;
784
785
/**
786
* No-operation function for testing/debugging
787
*/
788
no_op(): void;
789
```
790
791
## Properties
792
793
```javascript { .api }
794
interface Collection {
795
/** Collection name */
796
name: string;
797
/** Array of documents */
798
data: object[];
799
/** Collection configuration options */
800
options: CollectionOptions;
801
/** Binary indices for optimized querying */
802
binaryIndices: { [field: string]: any };
803
/** Unique field constraints */
804
constraints: { unique: { [field: string]: any } };
805
/** Array of dynamic views */
806
DynamicViews: DynamicView[];
807
/** Transform functions */
808
transforms: { [name: string]: any[] };
809
/** Maximum $loki id assigned */
810
maxId: number;
811
/** Dirty flag indicating unsaved changes */
812
dirty: boolean;
813
}
814
```