or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

changes-monitoring.mddatabase-management.mddocument-operations.mdindex.mdplugins-adapters.mdreplication-sync.md

changes-monitoring.mddocs/

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