0
# Index Management
1
2
Performance optimization through automatic and custom indexing including unique constraints, sparse indexes, and TTL (time-to-live) functionality for automatic document expiration.
3
4
## Capabilities
5
6
### Index Creation
7
8
Create indexes on specific fields to improve query performance with support for unique constraints and TTL expiration.
9
10
```javascript { .api }
11
/**
12
* Create or ensure index exists on specified field
13
* @param {object} options - Index configuration options
14
* @param {function} callback - Optional callback function (err) => {}
15
*/
16
ensureIndex(options, callback);
17
18
/**
19
* Index configuration options
20
*/
21
interface IndexOptions {
22
fieldName: string; // Field name to index (required)
23
unique?: boolean; // Enforce unique constraint (default: false)
24
sparse?: boolean; // Create sparse index, ignoring null/undefined values (default: false)
25
expireAfterSeconds?: number; // TTL in seconds for automatic document expiration
26
}
27
```
28
29
**Usage Examples:**
30
31
```javascript
32
const db = new Datastore({ filename: './users.db', autoload: true });
33
34
// Basic field index
35
db.ensureIndex({ fieldName: 'email' }, (err) => {
36
if (err) {
37
console.error('Failed to create email index:', err);
38
} else {
39
console.log('Email index created successfully');
40
}
41
});
42
43
// Unique index (prevents duplicate values)
44
db.ensureIndex({ fieldName: 'username', unique: true }, (err) => {
45
if (err) {
46
console.error('Failed to create unique username index:', err);
47
} else {
48
console.log('Unique username index created');
49
}
50
});
51
52
// Sparse index (ignores null/undefined values)
53
db.ensureIndex({ fieldName: 'phoneNumber', sparse: true }, (err) => {
54
if (!err) {
55
console.log('Sparse phone number index created');
56
}
57
});
58
59
// TTL index for automatic expiration
60
db.ensureIndex({
61
fieldName: 'expiresAt',
62
expireAfterSeconds: 3600 // 1 hour
63
}, (err) => {
64
if (!err) {
65
console.log('TTL index created - documents expire after 1 hour');
66
}
67
});
68
69
// Compound options
70
db.ensureIndex({
71
fieldName: 'sessionToken',
72
unique: true,
73
sparse: true,
74
expireAfterSeconds: 1800 // 30 minutes
75
}, (err) => {
76
if (!err) {
77
console.log('Unique, sparse TTL index on sessionToken created');
78
}
79
});
80
81
// Index on nested fields using dot notation
82
db.ensureIndex({ fieldName: 'profile.email' }, (err) => {
83
if (!err) {
84
console.log('Index created on nested email field');
85
}
86
});
87
```
88
89
### Index Removal
90
91
Remove existing indexes to free up memory and storage space.
92
93
```javascript { .api }
94
/**
95
* Remove index from specified field
96
* @param {string} fieldName - Name of field to remove index from
97
* @param {function} callback - Optional callback function (err) => {}
98
*/
99
removeIndex(fieldName, callback);
100
```
101
102
**Usage Examples:**
103
104
```javascript
105
const db = new Datastore({ filename: './users.db', autoload: true });
106
107
// Remove single index
108
db.removeIndex('email', (err) => {
109
if (err) {
110
console.error('Failed to remove email index:', err);
111
} else {
112
console.log('Email index removed successfully');
113
}
114
});
115
116
// Remove nested field index
117
db.removeIndex('profile.email', (err) => {
118
if (!err) {
119
console.log('Nested email index removed');
120
}
121
});
122
123
// Note: Cannot remove the automatic _id index
124
db.removeIndex('_id', (err) => {
125
console.log('Cannot remove _id index:', err.message);
126
});
127
```
128
129
### Index Information Access
130
131
Access information about existing indexes through database properties.
132
133
```javascript { .api }
134
/**
135
* Database index properties
136
*/
137
interface IndexProperties {
138
indexes: { [fieldName: string]: Index }; // Map of field names to Index objects
139
ttlIndexes: { [fieldName: string]: number }; // Map of TTL field names to expiration seconds
140
}
141
```
142
143
**Usage Examples:**
144
145
```javascript
146
const db = new Datastore({ filename: './users.db', autoload: true });
147
148
// List all indexed fields
149
console.log('Indexed fields:', Object.keys(db.indexes));
150
151
// Check if specific field is indexed
152
if (db.indexes['email']) {
153
console.log('Email field is indexed');
154
} else {
155
console.log('Email field is not indexed');
156
}
157
158
// List TTL indexes
159
console.log('TTL indexes:', db.ttlIndexes);
160
Object.keys(db.ttlIndexes).forEach(field => {
161
console.log(`- ${field}: expires after ${db.ttlIndexes[field]} seconds`);
162
});
163
164
// Index count
165
console.log('Total indexes:', Object.keys(db.indexes).length);
166
167
// Check for automatic _id index
168
console.log('_id index exists:', !!db.indexes['_id']);
169
```
170
171
### TTL (Time To Live) Indexes
172
173
Automatic document expiration based on date field values and configured TTL duration.
174
175
```javascript { .api }
176
/**
177
* TTL index configuration for automatic document expiration
178
* Documents are automatically removed when:
179
* document[fieldName] + expireAfterSeconds < currentTime
180
*/
181
interface TTLBehavior {
182
fieldName: string; // Must be a Date field
183
expireAfterSeconds: number; // Seconds after field date when document expires
184
}
185
```
186
187
**Usage Examples:**
188
189
```javascript
190
const db = new Datastore({ filename: './sessions.db', autoload: true });
191
192
// Create TTL index for session expiration
193
db.ensureIndex({
194
fieldName: 'createdAt',
195
expireAfterSeconds: 1800 // 30 minutes
196
}, (err) => {
197
if (!err) {
198
console.log('Session TTL index created');
199
}
200
});
201
202
// Insert documents with TTL field
203
const now = new Date();
204
db.insert([
205
{ sessionId: 'sess_1', userId: 'user1', createdAt: now },
206
{ sessionId: 'sess_2', userId: 'user2', createdAt: new Date(now.getTime() - 1000000) }
207
], (err, docs) => {
208
if (!err) {
209
console.log('Sessions inserted with TTL timestamps');
210
}
211
});
212
213
// TTL for log entries with custom expiration field
214
const logsDb = new Datastore({ filename: './logs.db', autoload: true });
215
216
logsDb.ensureIndex({
217
fieldName: 'expiresAt',
218
expireAfterSeconds: 0 // Expire exactly at the specified time
219
}, (err) => {
220
if (!err) {
221
console.log('Log expiration index created');
222
}
223
});
224
225
// Insert log with specific expiration time
226
const expireTime = new Date();
227
expireTime.setHours(expireTime.getHours() + 24); // Expire in 24 hours
228
229
logsDb.insert({
230
message: 'System started',
231
level: 'info',
232
timestamp: new Date(),
233
expiresAt: expireTime
234
}, (err, doc) => {
235
if (!err) {
236
console.log('Log entry inserted with 24-hour expiration');
237
}
238
});
239
240
// TTL for temporary data
241
const tempDb = new Datastore({ filename: './temp.db', autoload: true });
242
243
tempDb.ensureIndex({
244
fieldName: 'validUntil',
245
expireAfterSeconds: 300 // 5 minutes after validUntil date
246
}, (err) => {
247
if (!err) {
248
console.log('Temporary data TTL index created');
249
}
250
});
251
```
252
253
### Index Performance Impact
254
255
Understanding when and how to use indexes effectively for optimal database performance.
256
257
```javascript { .api }
258
/**
259
* Index performance characteristics
260
*/
261
interface IndexPerformance {
262
memoryUsage: 'proportional_to_document_count'; // Each index requires memory
263
insertSpeed: 'slower_with_more_indexes'; // More indexes = slower inserts
264
querySpeed: 'faster_on_indexed_fields'; // Indexed queries are much faster
265
uniqueConstraints: 'enforced_automatically'; // Unique indexes prevent duplicates
266
sparseIndexes: 'ignore_null_undefined'; // Sparse indexes save space
267
}
268
```
269
270
**Usage Examples:**
271
272
```javascript
273
const db = new Datastore({ filename: './products.db', autoload: true });
274
275
// Performance-conscious index creation
276
// Index frequently queried fields
277
db.ensureIndex({ fieldName: 'category' }); // Often used in filters
278
db.ensureIndex({ fieldName: 'price' }); // Often used in range queries
279
db.ensureIndex({ fieldName: 'sku', unique: true }); // Business requirement
280
281
// Avoid over-indexing
282
// Don't index fields that are rarely queried
283
// db.ensureIndex({ fieldName: 'description' }); // Rarely queried, skip
284
285
// Use sparse indexes for optional fields
286
db.ensureIndex({ fieldName: 'discountCode', sparse: true }); // Many nulls expected
287
288
// Measure query performance
289
const startTime = Date.now();
290
db.find({ category: 'electronics', price: { $lte: 500 } }, (err, products) => {
291
const queryTime = Date.now() - startTime;
292
console.log(`Query completed in ${queryTime}ms with ${products.length} results`);
293
});
294
295
// Monitor index effectiveness
296
db.find({ category: 'electronics' }, (err, products) => {
297
// This should be fast with category index
298
console.log('Found products by category (indexed):', products.length);
299
});
300
301
db.find({ description: { $regex: /smartphone/i } }, (err, products) => {
302
// This will be slower without description index
303
console.log('Found products by description (not indexed):', products.length);
304
});
305
```
306
307
### Index Best Practices
308
309
Guidelines for effective index usage in NeDB applications.
310
311
```javascript
312
// 1. Index frequently queried fields
313
db.ensureIndex({ fieldName: 'status' }); // if you often query by status
314
db.ensureIndex({ fieldName: 'userId' }); // if you often query by user
315
316
// 2. Use unique indexes for business constraints
317
db.ensureIndex({ fieldName: 'email', unique: true });
318
db.ensureIndex({ fieldName: 'productCode', unique: true });
319
320
// 3. Use sparse indexes for optional fields to save memory
321
db.ensureIndex({ fieldName: 'phoneNumber', sparse: true });
322
db.ensureIndex({ fieldName: 'middleName', sparse: true });
323
324
// 4. Create compound queries efficiently by indexing the most selective field
325
// For queries like: { category: 'books', price: { $lt: 20 } }
326
// If category has fewer distinct values, index price instead:
327
db.ensureIndex({ fieldName: 'price' });
328
329
// 5. Use TTL indexes for cleanup automation
330
db.ensureIndex({
331
fieldName: 'createdAt',
332
expireAfterSeconds: 86400 // Auto-remove day-old records
333
});
334
335
// 6. Remove unused indexes to improve insert performance
336
db.removeIndex('oldFieldName');
337
338
// 7. Monitor index usage and performance
339
console.log('Current indexes:', Object.keys(db.indexes));
340
console.log('TTL indexes:', db.ttlIndexes);
341
```
342
343
## Automatic Index Management
344
345
NeDB automatically manages the `_id` index and handles index updates during document operations. All document insertions, updates, and deletions automatically maintain index consistency without manual intervention.