|
1 | | -# jsonarrayfs <img alt="NPM Version" src="https://img.shields.io/npm/v/jsonarrayfs"> <img alt="Monthly Downloads" src="https://img.shields.io/npm/dm/jsonarrayfs" /> <img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/mochatek/jsonarrayfs/publish-to-npm.yml"> |
| 1 | +# jsonarrayfs |
2 | 2 |
|
3 | | -"jsonarrayfs" is a Node.js library crafted for robust and memory-efficient management of massive JSON array files. It enables seamless handling of JSON arrays without the need to load the entire file into memory, making it perfect for efficiently managing large datasets without overwhelming system resources. |
| 3 | +[](https://www.npmjs.com/package/jsonarrayfs) |
| 4 | +[](https://www.npmjs.com/package/jsonarrayfs) |
| 5 | +[](https://opensource.org/licenses/MIT) |
| 6 | + |
4 | 7 |
|
5 | | -## 🎯 Key Features |
| 8 | +Specialized Node.js library for memory-efficient operations on JSON array files. Stream individual elements from large JSON array files and append new elements without loading the entire array into memory. Perfect for processing large-scale JSON array datasets without memory limitations. |
6 | 9 |
|
7 | | -- **Stream Processing**: Read JSON array in manageable chunks (eg: 50k elements at a time) using stream. |
8 | | -- **On-the-Fly Filtering**: Apply filter to the stream to fetch only relevant data, reducing the data you handle even further. |
9 | | -- **Direct Appends**: Append new elements directly to the JSON array file, avoiding unnecessary loading, modification and rewriting. |
10 | | -- **Formatting Flexibility**: Works regardless of whether the JSON file is formatted with proper indentation or not. |
11 | | -- **Handles Mixed Types**: Can handle JSON arrays containing both uniform and mixed types of elements. |
| 10 | +## Why Use This? |
12 | 11 |
|
13 | | -## 💡 Benefits |
| 12 | +- 🎯 **Specialized**: Purpose-built for JSON array files |
| 13 | +- 💾 **Memory Efficient**: Process arrays of any size without loading them entirely |
| 14 | +- ⚡ **High Performance**: Optimized streaming and batch operations |
| 15 | +- ✍️ **Direct Updates**: Append elements without rewriting the entire file |
| 16 | +- 🔄 **Format Agnostic**: Works with any valid JSON array structure |
14 | 17 |
|
15 | | -- **Memory Optimization**: Process JSON array files with minimal memory usage, making it ideal for resource-constrained environments. |
16 | | -- **Handles Large Datasets**: Efficiently manage massive JSON array files without memory limitations. |
17 | | -- **Improved Performance**: Faster processing times due to efficient streaming, filtering and appending capabilities. |
18 | | -- **Enhanced Scalability**: Scales seamlessly with growing datasets, ensuring smooth performance. |
| 18 | +## Installation |
19 | 19 |
|
20 | | -## ⚙️ Installation |
21 | | - |
22 | | -To install jsonarrayfs, use: |
23 | | - |
24 | | -```sh |
| 20 | +```bash |
25 | 21 | npm install jsonarrayfs |
26 | 22 | ``` |
27 | 23 |
|
28 | | -## 🚀 Usage |
| 24 | +## Usage |
| 25 | + |
| 26 | +```typescript |
| 27 | +import { JsonArrayStream, appendToJsonArrayFile } from "jsonarrayfs"; |
| 28 | +import { createReadStream } from "node:fs"; |
| 29 | +import { Transform } from "node:stream"; |
| 30 | + |
| 31 | +// Process a large application log file (10GB+ JSON array) |
| 32 | +const fileStream = createReadStream("app.log.json"); |
| 33 | +const arrayStream = new JsonArrayStream("utf8"); |
| 34 | + |
| 35 | +// Analyze logs: Count errors and slow responses |
| 36 | +let errorCount = 0; |
| 37 | +let slowResponses = 0; |
| 38 | + |
| 39 | +for await (const log of fileStream.pipe(arrayStream)) { |
| 40 | + if (log !== JsonArrayStream.NULL) { |
| 41 | + if (log.level === "error") { |
| 42 | + errorCount++; |
| 43 | + console.error(`Error in ${log.service}: ${log.message}`); |
| 44 | + } |
| 45 | + |
| 46 | + if (log.responseTime > 1000) { |
| 47 | + slowResponses++; |
| 48 | + console.warn(`Slow response: ${log.path} (${log.responseTime}ms)`); |
| 49 | + } |
| 50 | + } |
| 51 | +} |
29 | 52 |
|
30 | | -- Stream Processing: |
| 53 | +console.log( |
| 54 | + `Analysis complete: ${errorCount} errors, ${slowResponses} slow responses`, |
| 55 | +); |
31 | 56 |
|
32 | | -```ts |
33 | | -import { createReadStream } from "jsonarrayfs"; |
| 57 | +// Append new log entries |
| 58 | +const newLogs = [ |
| 59 | + { |
| 60 | + timestamp: Date.now(), |
| 61 | + level: "info", |
| 62 | + service: "auth", |
| 63 | + path: "/api/login", |
| 64 | + responseTime: 245, |
| 65 | + message: "User login successful", |
| 66 | + }, |
| 67 | + { |
| 68 | + timestamp: Date.now(), |
| 69 | + level: "info", |
| 70 | + service: "auth", |
| 71 | + path: "/api/login", |
| 72 | + responseTime: 1245, |
| 73 | + message: "User login successful", |
| 74 | + }, |
| 75 | + null, |
| 76 | + { |
| 77 | + timestamp: Date.now(), |
| 78 | + level: "error", |
| 79 | + service: "payment", |
| 80 | + path: "/api/checkout", |
| 81 | + responseTime: 1532, |
| 82 | + message: "Database connection timeout", |
| 83 | + }, |
| 84 | +]; |
34 | 85 |
|
35 | | -// Option 1: Create a streamer to read JSON array elements from a file |
36 | | -const streamer = await createReadStream("./data.json", { encoding: "utf-8" }); |
| 86 | +await appendToJsonArrayFile("app.log.json", "utf8", ...newLogs); |
| 87 | +``` |
37 | 88 |
|
38 | | -// Option 2: Create a streamer to read JSON array elements from an existing Readable: |
| 89 | +## API |
39 | 90 |
|
40 | | -// From a file |
41 | | -import fs from "fs"; |
42 | | -const readStream = fs.createReadStream("./data.json", { encoding: "utf-8" }); |
43 | | -const streamer = await createReadStream(readStream); |
| 91 | +### JsonArrayStream |
44 | 92 |
|
45 | | -// From an API response |
46 | | -import { ReadableStream } from "stream/web"; |
47 | | -import { Readable } from "stream"; |
48 | | -const response = await fetch("https://www.example.com/json-data"); |
49 | | -const readableStream = Readable.fromWeb( |
50 | | - response.body as unknown as ReadableStream, |
51 | | -); |
52 | | -const streamer = await createReadStream(readableStream); |
| 93 | +A transform stream that reads JSON array files and emits elements one by one for efficient processing. When processing arrays containing `null` values, it uses a special sentinel value (`JsonArrayStream.NULL`) to distinguish between JSON `null` and stream EOF. |
53 | 94 |
|
54 | | -// Stream JSON array elements in batches of 100 |
55 | | -for await (const elements of streamer.batch(100)) { |
56 | | - // Your processing logic here |
57 | | -} |
| 95 | +#### Constructor |
| 96 | + |
| 97 | +```typescript |
| 98 | +new JsonArrayStream(encoding?: string) |
58 | 99 | ``` |
59 | 100 |
|
60 | | -- On-the-Fly Filtering: |
| 101 | +##### Parameters |
61 | 102 |
|
62 | | -```ts |
63 | | -import { createReadStream } from "jsonarrayfs"; |
| 103 | +- `encoding` (string, optional): File encoding (default: 'utf8') |
64 | 104 |
|
65 | | -const streamer = await createReadStream<{ offer: boolean; price: number }>( |
66 | | - "./data.json", |
67 | | - { encoding: "utf-8" }, |
68 | | -); |
| 105 | +#### Properties |
69 | 106 |
|
70 | | -// Add filter to the batch to fetch only relevant elements |
71 | | -for await (const elements of streamer.batch( |
72 | | - 100, |
73 | | - (element) => element.price < 500 || element.offer, |
74 | | -)) { |
75 | | - // Your processing logic here |
76 | | -} |
77 | | -``` |
| 107 | +- `JsonArrayStream.NULL`: Special sentinel value to distinguish between JSON `null` and stream EOF |
78 | 108 |
|
79 | | -- Append data to existing JSON array: |
| 109 | +#### Events |
80 | 110 |
|
81 | | -```ts |
82 | | -import { appendFile } from "jsonarrayfs"; |
| 111 | +- `data`: Emitted for each array element |
| 112 | +- `error`: Emitted when parsing fails or input is invalid |
83 | 113 |
|
84 | | -// Simulate new data to append |
85 | | -const newData = [ |
86 | | - { id: 1, name: "Earth", price: 1000, offer: true }, |
87 | | - { id: 2, name: "Moon", price: 500, offer: false }, |
88 | | -]; |
| 114 | +### appendToJsonArrayFile |
89 | 115 |
|
90 | | -// Append new data to the existing JSON array file |
91 | | -await appendFile("./data.json", "utf-8", ...newData); |
| 116 | +Appends elements to a JSON array file efficiently without loading the entire file into memory. |
| 117 | + |
| 118 | +#### Signature |
| 119 | + |
| 120 | +```typescript |
| 121 | +async function appendToJsonArrayFile( |
| 122 | + filePath: string, |
| 123 | + encoding?: string, |
| 124 | + ...elements: any[] |
| 125 | +): Promise<void>; |
92 | 126 | ``` |
93 | 127 |
|
94 | | -## 🤝 Contributing |
| 128 | +#### Parameters |
| 129 | + |
| 130 | +- `filePath` (string): Path to the JSON array file |
| 131 | +- `encoding` (string, optional): File encoding (default: 'utf8') |
| 132 | +- `...elements` (any[]): Elements to append to the array |
| 133 | + |
| 134 | +#### Returns |
| 135 | + |
| 136 | +Promise that resolves when the append operation is complete. |
| 137 | + |
| 138 | +## Error Handling |
| 139 | + |
| 140 | +The library can throw these errors: |
| 141 | + |
| 142 | +### `JsonArrayStreamError` |
| 143 | + |
| 144 | +- Invalid JSON array format |
| 145 | +- Malformed array elements |
| 146 | +- Unexpected end of input |
| 147 | + |
| 148 | +### `JsonArrayAppendError` |
| 149 | + |
| 150 | +- Invalid JSON array format |
| 151 | +- File system errors |
| 152 | +- Permission issues |
| 153 | +- Invalid input elements |
| 154 | + |
| 155 | +## Requirements |
95 | 156 |
|
96 | | -Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. |
| 157 | +- Node.js >= 16.0.0 |
| 158 | +- Input file must be a valid JSON array |
97 | 159 |
|
98 | | -## 📜 License |
| 160 | +## License |
99 | 161 |
|
100 | | -[MIT License ](https://github.com/mochatek/jsonarrayfs/blob/main/LICENSE) |
| 162 | +MIT License - see the [LICENSE](LICENSE) file for details |
0 commit comments