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
```