0
# Changes and Monitoring
1
2
Real-time monitoring of database changes with filtering, continuous feeds, and event-driven updates. The changes feed is essential for building reactive applications and implementing real-time synchronization.
3
4
## Capabilities
5
6
### Changes Feed
7
8
Monitors database changes with support for continuous feeds, filtering, and detailed change information.
9
10
```javascript { .api }
11
/**
12
* Monitor database changes with various options
13
* @param options - Options for changes monitoring
14
* @returns Changes object with event emitter interface
15
*/
16
db.changes(options?: ChangesOptions): Changes;
17
18
interface ChangesOptions {
19
since?: number | string; // Starting sequence number or 'now'
20
limit?: number; // Maximum number of changes to return
21
descending?: boolean; // Return changes in reverse order
22
include_docs?: boolean; // Include full document content
23
conflicts?: boolean; // Include conflicting revisions
24
attachments?: boolean; // Include attachment data
25
live?: boolean; // Continuous changes feed
26
continuous?: boolean; // Alias for live
27
heartbeat?: number; // Heartbeat interval (milliseconds)
28
timeout?: number; // Request timeout (milliseconds)
29
filter?: string | Function; // Filter function or design doc filter
30
view?: string; // View-based filter
31
doc_ids?: string[]; // Monitor specific document IDs only
32
query_params?: object; // Parameters for filter functions
33
}
34
35
interface Changes extends EventEmitter {
36
cancel(): void; // Stop the changes feed
37
on(event: 'change', listener: (info: ChangeInfo) => void): Changes;
38
on(event: 'complete', listener: (info: ChangesComplete) => void): Changes;
39
on(event: 'error', listener: (error: Error) => void): Changes;
40
}
41
42
interface ChangeInfo {
43
id: string; // Document ID
44
seq: number | string; // Sequence number
45
changes: ChangeItem[]; // Array of changes
46
doc?: Document; // Full document (if include_docs: true)
47
deleted?: boolean; // Whether document was deleted
48
}
49
50
interface ChangeItem {
51
rev: string; // Revision ID
52
}
53
54
interface ChangesComplete {
55
results: ChangeInfo[]; // All changes (for non-live feeds)
56
last_seq: number | string; // Last sequence number
57
}
58
```
59
60
**Usage Examples:**
61
62
```javascript
63
// Basic changes monitoring
64
const changes = db.changes({
65
since: 'now',
66
live: true,
67
include_docs: true
68
}).on('change', function(info) {
69
console.log('Document changed:', info.id);
70
if (info.deleted) {
71
console.log('Document was deleted');
72
} else {
73
console.log('New revision:', info.doc._rev);
74
}
75
}).on('complete', function(info) {
76
console.log('Changes feed complete');
77
}).on('error', function(err) {
78
console.error('Changes feed error:', err);
79
});
80
81
// Stop the changes feed
82
setTimeout(() => {
83
changes.cancel();
84
}, 30000); // Stop after 30 seconds
85
```
86
87
### Historical Changes
88
89
Retrieve changes that occurred in the past with pagination and filtering.
90
91
```javascript
92
// Get recent changes (non-live)
93
const result = await new Promise((resolve, reject) => {
94
db.changes({
95
limit: 50,
96
include_docs: true
97
}).on('complete', resolve).on('error', reject);
98
});
99
100
console.log(`Found ${result.results.length} changes`);
101
result.results.forEach(change => {
102
console.log(`${change.id}: ${change.changes[0].rev}`);
103
});
104
105
// Get changes since specific sequence
106
const recentChanges = await new Promise((resolve, reject) => {
107
db.changes({
108
since: 100,
109
limit: 20
110
}).on('complete', resolve).on('error', reject);
111
});
112
```
113
114
### Filtered Changes
115
116
Monitor changes for specific documents or using custom filter functions.
117
118
```javascript
119
// Monitor specific documents only
120
const specificChanges = db.changes({
121
live: true,
122
doc_ids: ['user1', 'user2', 'user3'],
123
include_docs: true
124
}).on('change', function(info) {
125
console.log(`User document changed: ${info.id}`);
126
});
127
128
// Custom filter function
129
const filteredChanges = db.changes({
130
live: true,
131
include_docs: true,
132
filter: function(doc) {
133
return doc.type === 'user' && doc.active === true;
134
}
135
}).on('change', function(info) {
136
console.log('Active user changed:', info.doc.name);
137
});
138
139
// Filter with parameters
140
const parameterizedChanges = db.changes({
141
live: true,
142
filter: 'myapp/users', // Design document filter
143
query_params: {
144
department: 'engineering',
145
active: true
146
}
147
});
148
```
149
150
### Continuous Changes with Heartbeat
151
152
Set up reliable continuous monitoring with heartbeat and error handling.
153
154
```javascript
155
function startChangesMonitoring() {
156
const changes = db.changes({
157
live: true,
158
since: 'now',
159
heartbeat: 10000, // 10 second heartbeat
160
timeout: 30000, // 30 second timeout
161
include_docs: true,
162
retry: true
163
});
164
165
changes.on('change', function(info) {
166
console.log('Change detected:', info.id);
167
processChange(info);
168
});
169
170
changes.on('error', function(err) {
171
console.error('Changes feed error:', err);
172
// Restart after delay
173
setTimeout(startChangesMonitoring, 5000);
174
});
175
176
changes.on('complete', function(info) {
177
console.log('Changes feed completed');
178
// Restart if needed
179
setTimeout(startChangesMonitoring, 1000);
180
});
181
182
return changes;
183
}
184
185
function processChange(changeInfo) {
186
if (changeInfo.deleted) {
187
handleDocumentDeletion(changeInfo.id);
188
} else {
189
handleDocumentUpdate(changeInfo.doc);
190
}
191
}
192
193
// Start monitoring
194
const changesMonitor = startChangesMonitoring();
195
196
// Stop monitoring when needed
197
function stopMonitoring() {
198
changesMonitor.cancel();
199
}
200
```
201
202
### Change Sequence Management
203
204
Work with sequence numbers for resuming changes feeds and synchronization.
205
206
```javascript
207
// Store last sequence for resumption
208
let lastSequence = null;
209
210
const changes = db.changes({
211
since: lastSequence || 0,
212
live: true,
213
include_docs: true
214
}).on('change', function(info) {
215
// Update last sequence
216
lastSequence = info.seq;
217
localStorage.setItem('lastSequence', lastSequence);
218
219
console.log(`Processed change ${info.id} at sequence ${info.seq}`);
220
}).on('complete', function(info) {
221
// Save final sequence
222
if (info.last_seq) {
223
lastSequence = info.last_seq;
224
localStorage.setItem('lastSequence', lastSequence);
225
}
226
});
227
228
// Resume from stored sequence on restart
229
function resumeChanges() {
230
const storedSequence = localStorage.getItem('lastSequence');
231
return db.changes({
232
since: storedSequence || 'now',
233
live: true,
234
include_docs: true
235
});
236
}
237
```
238
239
### Changes with Conflicts
240
241
Monitor and handle document conflicts in replicated environments.
242
243
```javascript
244
const conflictMonitor = db.changes({
245
live: true,
246
include_docs: true,
247
conflicts: true
248
}).on('change', function(info) {
249
if (info.doc._conflicts && info.doc._conflicts.length > 0) {
250
console.log(`Conflict detected in document ${info.id}`);
251
handleConflict(info.doc);
252
}
253
});
254
255
async function handleConflict(doc) {
256
console.log(`Document ${doc._id} has conflicts:`, doc._conflicts);
257
258
// Get all conflicting revisions
259
const conflicts = await Promise.all(
260
doc._conflicts.map(rev => db.get(doc._id, { rev }))
261
);
262
263
// Implement conflict resolution logic
264
const resolved = resolveConflict(doc, conflicts);
265
266
// Save resolved document
267
await db.put(resolved);
268
269
// Remove conflicting revisions
270
for (const conflict of conflicts) {
271
await db.remove(conflict);
272
}
273
}
274
275
function resolveConflict(mainDoc, conflictDocs) {
276
// Implement your conflict resolution strategy
277
// This example uses "last write wins" based on timestamp
278
const allDocs = [mainDoc, ...conflictDocs];
279
return allDocs.reduce((latest, current) => {
280
const latestTime = new Date(latest.updated || 0);
281
const currentTime = new Date(current.updated || 0);
282
return currentTime > latestTime ? current : latest;
283
});
284
}
285
```
286
287
## Event Handling Patterns
288
289
### Promise-based Changes
290
291
Convert changes feed to Promise for one-time change retrieval:
292
293
```javascript
294
// Get changes as Promise
295
function getChanges(options) {
296
return new Promise((resolve, reject) => {
297
db.changes(options)
298
.on('complete', resolve)
299
.on('error', reject);
300
});
301
}
302
303
// Usage
304
const changes = await getChanges({
305
since: 'now',
306
limit: 10,
307
include_docs: true
308
});
309
310
console.log(`Received ${changes.results.length} changes`);
311
```
312
313
### Async Iterator Pattern
314
315
Create async iterator for changes processing:
316
317
```javascript
318
async function* changesIterator(options) {
319
const changes = db.changes({ ...options, live: true });
320
321
try {
322
while (true) {
323
const change = await new Promise((resolve, reject) => {
324
changes.once('change', resolve);
325
changes.once('error', reject);
326
changes.once('complete', () => resolve(null));
327
});
328
329
if (change === null) break; // Complete
330
yield change;
331
}
332
} finally {
333
changes.cancel();
334
}
335
}
336
337
// Usage
338
for await (const change of changesIterator({ include_docs: true })) {
339
console.log('Processing change:', change.id);
340
await processChange(change);
341
}
342
```
343
344
## Error Handling
345
346
Handle various error scenarios in changes monitoring:
347
348
```javascript
349
const changes = db.changes({
350
live: true,
351
since: 'now'
352
}).on('change', function(info) {
353
console.log('Change:', info.id);
354
}).on('error', function(err) {
355
if (err.status === 401) {
356
console.log('Authentication required');
357
// Handle auth error
358
} else if (err.status === 404) {
359
console.log('Database not found');
360
// Handle missing database
361
} else if (err.name === 'timeout') {
362
console.log('Changes feed timeout');
363
// Restart feed
364
} else {
365
console.error('Unexpected error:', err);
366
}
367
});
368
```
369
370
Common error scenarios:
371
- Network timeouts during continuous monitoring
372
- Authentication failures for remote databases
373
- Database deletion while monitoring changes
374
- Invalid filter functions or parameters