or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

adapters.mdadvanced-features.mddatabase-operations.mdindex.md

advanced-features.mddocs/

0

# Advanced Features

1

2

Advanced functionality including array operations, search capabilities, database management, locking, and path utilities for complex data scenarios.

3

4

## Capabilities

5

6

### Array Operations

7

8

#### Count Array Elements

9

10

Returns the number of elements in an array at the specified DataPath.

11

12

```typescript { .api }

13

/**

14

* Returns the number of element which constitutes the array

15

* @param dataPath - Path to the array

16

* @returns Promise resolving to array length

17

* @throws DataError if the path doesn't point to an array

18

*/

19

count(dataPath: string): Promise<number>;

20

```

21

22

**Usage Examples:**

23

24

```typescript

25

// Count users

26

const userCount = await db.count("/users");

27

28

// Count nested array

29

const tagCount = await db.count("/posts/1/tags");

30

31

// Works with multi-dimensional arrays

32

const matrixRows = await db.count("/matrix");

33

const matrixCols = await db.count("/matrix/0");

34

```

35

36

#### Get Object Index

37

38

Finds the index of an object in an array based on a property value.

39

40

```typescript { .api }

41

/**

42

* Returns the index of the object that meets the criteria submitted. Returns -1, if no match is found.

43

* @param dataPath - Base dataPath from where to start searching

44

* @param searchValue - Value to look for in the specified property

45

* @param propertyName - Name of the property to look for searchValue (default: "id")

46

* @returns Promise resolving to index or -1 if not found

47

*/

48

getIndex(

49

dataPath: string,

50

searchValue: string | number,

51

propertyName?: string

52

): Promise<number>;

53

```

54

55

**Usage Examples:**

56

57

```typescript

58

// Find user by ID (default property name)

59

const userIndex = await db.getIndex("/users", 123);

60

61

// Find user by email

62

const emailIndex = await db.getIndex("/users", "alice@example.com", "email");

63

64

// Find post by title

65

const postIndex = await db.getIndex("/posts", "My First Post", "title");

66

67

// Use result for further operations

68

if (userIndex !== -1) {

69

const user = await db.getData(`/users/${userIndex}`);

70

}

71

```

72

73

#### Get Value Index

74

75

Finds the index of a primitive value in an array.

76

77

```typescript { .api }

78

/**

79

* Return the index of the value inside the array. Returns -1, if no match is found.

80

* @param dataPath - Base dataPath from where to start searching

81

* @param searchValue - Value to look for in the array

82

* @returns Promise resolving to index or -1 if not found

83

*/

84

getIndexValue(dataPath: string, searchValue: string | number): Promise<number>;

85

```

86

87

**Usage Examples:**

88

89

```typescript

90

// Find value in simple array

91

const tagIndex = await db.getIndexValue("/posts/1/tags", "javascript");

92

93

// Find number in array

94

const scoreIndex = await db.getIndexValue("/game/scores", 1500);

95

96

// Use with array operations

97

if (tagIndex === -1) {

98

await db.push("/posts/1/tags", ["javascript"], false); // Add if not exists

99

}

100

```

101

102

### Search Operations

103

104

#### Filter Entries

105

106

Searches for all entries matching a callback predicate function in arrays or objects.

107

108

```typescript { .api }

109

/**

110

* Find all specific entry in an array/object

111

* @param rootPath - Base dataPath from where to start searching

112

* @param callback - Method to filter the result and find the wanted entry. Receive the entry and its index.

113

* @returns Promise resolving to array of matching entries or undefined if none found

114

* @throws DataError if the path doesn't point to an array or object

115

*/

116

filter<T>(rootPath: string, callback: FindCallback): Promise<T[] | undefined>;

117

```

118

119

**Usage Examples:**

120

121

```typescript

122

import { FindCallback } from "node-json-db";

123

124

// Filter active users

125

const activeUsers = await db.filter<User>("/users", (user, index) => {

126

return user.active === true;

127

});

128

129

// Filter posts by author

130

const alicePosts = await db.filter<Post>("/posts", (post, index) => {

131

return post.author === "Alice";

132

});

133

134

// Filter with complex conditions

135

const recentPosts = await db.filter<Post>("/posts", (post, index) => {

136

const oneWeekAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);

137

return new Date(post.createdAt).getTime() > oneWeekAgo;

138

});

139

140

// Filter object properties (index will be property name)

141

const configs = await db.filter<any>("/settings", (value, key) => {

142

return typeof value === "string" && key.startsWith("api_");

143

});

144

```

145

146

#### Find Single Entry

147

148

Searches for the first entry matching a callback predicate function in arrays or objects.

149

150

```typescript { .api }

151

/**

152

* Find a specific entry in an array/object

153

* @param rootPath - Base dataPath from where to start searching

154

* @param callback - Method to filter the result and find the wanted entry. Receive the entry and its index.

155

* @returns Promise resolving to the first matching entry or undefined if none found

156

* @throws DataError if the path doesn't point to an array or object

157

*/

158

find<T>(rootPath: string, callback: FindCallback): Promise<T | undefined>;

159

```

160

161

**Usage Examples:**

162

163

```typescript

164

// Find user by email

165

const user = await db.find<User>("/users", (user, index) => {

166

return user.email === "alice@example.com";

167

});

168

169

// Find first post with specific tag

170

const jsPost = await db.find<Post>("/posts", (post, index) => {

171

return post.tags.includes("javascript");

172

});

173

174

// Find configuration by key

175

const dbConfig = await db.find<any>("/settings", (value, key) => {

176

return key === "database_url";

177

});

178

179

// Complex search with multiple conditions

180

const targetUser = await db.find<User>("/users", (user, index) => {

181

return user.age >= 18 && user.verified && user.role === "admin";

182

});

183

```

184

185

#### FindCallback Type

186

187

Type definition for search callback functions.

188

189

```typescript { .api }

190

/**

191

* Callback function for find/filter operations

192

* @param entry - The current entry being evaluated

193

* @param index - For arrays: numeric index, for objects: property name

194

* @returns Boolean indicating if entry matches search criteria

195

*/

196

type FindCallback = (entry: any, index: number | string) => boolean;

197

```

198

199

### Path Utilities

200

201

#### Router Path Conversion

202

203

Converts router-style paths to DataPath format for accessing nested array elements.

204

205

```typescript { .api }

206

/**

207

* Convert a router style path to a normal path

208

* By default propertyName to search is "id"

209

* @param path - Router based path to convert (e.g., "/users/123/posts/456")

210

* @param propertyName - Name of the property to look for searchValue (default: "id")

211

* @returns Promise resolving to DataPath format

212

* @throws DataError if any part of the path is not found

213

*/

214

fromPath(path: string, propertyName?: string): Promise<string>;

215

```

216

217

**Usage Examples:**

218

219

```typescript

220

// Convert router path to DataPath

221

// Assumes users array with objects having "id" property

222

const dataPath = await db.fromPath("/users/123/posts/456");

223

// Result: "/users[2]/posts[1]" (if user with id 123 is at index 2, etc.)

224

225

// Use custom property name

226

const pathByEmail = await db.fromPath("/users/alice@example.com", "email");

227

// Result: "/users[0]" (if user with that email is at index 0)

228

229

// Use the converted path

230

const userData = await db.getData(dataPath);

231

232

// Multi-level conversion

233

const commentPath = await db.fromPath("/posts/1/comments/5/replies/2");

234

// Result: "/posts[0]/comments[4]/replies[1]"

235

```

236

237

**Router Path Format:**

238

- Input: `/collection/identifier/subcollection/identifier`

239

- Output: `/collection[index]/subcollection[index]`

240

241

### Concurrent Access Safety

242

243

Node JSON DB includes built-in read/write locking for concurrent access safety. All JsonDB methods automatically use appropriate locks internally to ensure data integrity during concurrent operations.

244

245

**Automatic Locking:**

246

- Read operations (getData, exists, count, etc.) use read locks

247

- Write operations (push, delete, save, etc.) use write locks

248

- Multiple reads can occur simultaneously

249

- Write operations are exclusive and block all other operations

250

251

**Concurrent Usage Example:**

252

253

```typescript

254

// Safe concurrent access - automatic locking handles this

255

const db = new JsonDB(new Config("shared.json"));

256

257

// Multiple processes/threads can safely access the same database

258

await Promise.all([

259

db.getData("/users/1"), // Read operation

260

db.getData("/users/2"), // Read operation

261

db.push("/users/3", data), // Write operation (will wait for reads)

262

db.count("/posts") // Read operation

263

]);

264

```

265

266

### Array Indexing Features

267

268

#### Standard Array Access

269

270

```typescript

271

// Basic array access

272

await db.getData("/users/0"); // First user

273

await db.getData("/users/1"); // Second user

274

275

// Nested array access

276

await db.getData("/posts/0/tags/1"); // Second tag of first post

277

```

278

279

#### Negative Array Indexing

280

281

```typescript

282

// Negative indexing (from end)

283

await db.getData("/users[-1]"); // Last user

284

await db.getData("/users[-2]"); // Second to last user

285

286

// Works with nested arrays

287

await db.getData("/posts/0/tags[-1]"); // Last tag of first post

288

```

289

290

#### Array Append Operations

291

292

```typescript

293

// Append to array using empty brackets

294

await db.push("/users[]", newUser);

295

296

// Append to nested array

297

await db.push("/posts/0/comments[]", newComment);

298

299

// Multi-dimensional append

300

await db.push("/matrix[]", newRow);

301

await db.push("/matrix[0][]", newValue);

302

```

303

304

#### Multi-dimensional Arrays

305

306

```typescript

307

// Access 2D array

308

await db.getData("/matrix[0][1]");

309

310

// Append to 2D array

311

await db.push("/matrix[0][]", newValue);

312

313

// 3D array access

314

await db.getData("/cube[0][1][2]");

315

```

316

317

318

### Performance Considerations

319

320

#### Batch Operations

321

322

```typescript

323

// For multiple related updates, consider using merge mode

324

await db.push("/users/1", {

325

name: "Alice",

326

email: "alice@example.com",

327

updated: new Date()

328

}, false); // merge with existing data

329

330

// Or disable auto-save for multiple operations, then save manually

331

const db = new JsonDB(new Config("database.json", false)); // saveOnPush = false

332

333

await db.push("/users/1/name", "Alice");

334

await db.push("/users/1/email", "alice@example.com");

335

await db.push("/users/1/updated", new Date());

336

await db.save(); // Save all changes at once

337

```

338

339

#### Large Array Operations

340

341

```typescript

342

// For large arrays, use filter/find instead of loading entire arrays

343

const activeUsers = await db.filter<User>("/users", user => user.active);

344

345

// Rather than:

346

const allUsers = await db.getData("/users");

347

const activeUsers = allUsers.filter(user => user.active);

348

```

349

350

#### Memory Management

351

352

```typescript

353

// Reload periodically for long-running processes

354

setInterval(async () => {

355

await db.reload();

356

}, 300000); // Every 5 minutes

357

358

// Use getObjectDefault to avoid exceptions

359

const settings = await db.getObjectDefault("/settings", defaultSettings);

360

```