1 | # Overview
|
2 |
|
3 | This project is inspired by [nedb](https://github.com/louischatriot/nedb).
|
4 | It aims to create a flexible database without any weird syntax or rules.
|
5 | Just few APIs will make everything work smoothly.
|
6 | JDB is an append-only, in-memory, non-block IO database.
|
7 |
|
8 | It uses json to decrease database file size, which means after all javascript commands are executed,
|
9 | they will become a single json object.
|
10 |
|
11 | For further infomation goto [How it works?](#user-content-how-it-works)
|
12 |
|
13 | [![Build Status](https://travis-ci.org/ysmood/jdb.svg)](https://travis-ci.org/ysmood/jdb) [![Build status](https://ci.appveyor.com/api/projects/status/ivsm326en792xsnj)](https://ci.appveyor.com/project/ysmood/jdb)
|
14 |
|
15 | # Features
|
16 |
|
17 | * Super fast ([see the benchmark](#user-content-benchmarks)).
|
18 |
|
19 | * Light weight. Core code is only about 200 lines.
|
20 |
|
21 | * Promise support.
|
22 |
|
23 | * Use full functioned javascript to operate your data, no steep learning curve.
|
24 |
|
25 | * Make debugging inside the data possible.
|
26 |
|
27 | * Support both standalone mode (server) and in-application mode (lib).
|
28 |
|
29 |
|
30 | # Quick start
|
31 |
|
32 | ### Installation
|
33 |
|
34 | Install `jdb` first.
|
35 |
|
36 | npm install jdb
|
37 |
|
38 | ### Examples
|
39 |
|
40 | Here's the embedded mode example.
|
41 |
|
42 | ```coffeescript
|
43 |
|
44 | jdb = require 'jdb'
|
45 |
|
46 | # The data to play with.
|
47 | some_data = {
|
48 | "name": {
|
49 | "first": "Yad"
|
50 | "last": "Smood"
|
51 | }
|
52 | "fav_color": "blue"
|
53 | "languages": [
|
54 | {
|
55 | "name": "Chinese"
|
56 | "level": 10
|
57 | }
|
58 | {
|
59 | "name": "English"
|
60 | "level": 8
|
61 | "preferred": true
|
62 | }
|
63 | {
|
64 | "name": "Japenese"
|
65 | "level": 6
|
66 | }
|
67 | ]
|
68 | "height": 180
|
69 | "weight": 68
|
70 | }
|
71 |
|
72 | # Init the db file before you start.
|
73 | jdb.init()
|
74 | .then ->
|
75 |
|
76 | # Set data.
|
77 | jdb.exec
|
78 | data: some_data
|
79 | command: (jdb, data) ->
|
80 | jdb.doc.ys = data
|
81 | jdb.save 'saved'
|
82 | callback: (err, data) ->
|
83 | console.log data # output >> saved
|
84 |
|
85 | # Or simple way to save data.
|
86 | jdb.exec some_data, (jdb, data) ->
|
87 | jdb.doc.arr = data.languages.map (el) -> el.name
|
88 | jdb.save()
|
89 | .then ->
|
90 | console.log 'saved'
|
91 |
|
92 | # Don't do something like this!
|
93 | wrong = ->
|
94 | jdb.exec command: (jdb) ->
|
95 | # Error: the scope here should not access the variable `some_data`.
|
96 | jdb.doc.ys = some_data
|
97 | jdb.save()
|
98 |
|
99 | # Get the value. Much simpler.
|
100 | console.log jdb.doc.ys.name # output >> [ "Yad", "Smood" ]
|
101 |
|
102 | ```
|
103 |
|
104 | # Http server quick start
|
105 |
|
106 | To allow JDB to serve multiple clients, you can start it as a http server (standalone mode).
|
107 |
|
108 | Install `jdb` globally.
|
109 |
|
110 | npm install -g jdb
|
111 |
|
112 | See help info.
|
113 |
|
114 | jdb -h
|
115 |
|
116 | Interactive mode, you have two global api.
|
117 | You can manipulate the data via `doc`, and run `save()` to permanent your change.
|
118 |
|
119 | jdb -i
|
120 |
|
121 | Start server at port 8081.
|
122 |
|
123 | jdb -p 8081
|
124 |
|
125 | JDB action `exec` only accepts raw `json` http request (do not url-encode the body!). For example:
|
126 |
|
127 | POST /exec HTTP/1.1
|
128 | Host: 127.0.0.1:8081
|
129 | Content-Length: 88
|
130 |
|
131 | { "data": 10, "command": "function(jdb, data) { jdb.doc.a = 1; jdb.save(jdb.doc); }" }
|
132 |
|
133 | It will return json:
|
134 |
|
135 | {"a":1}
|
136 |
|
137 | JDB action `compactDBFile` example:
|
138 |
|
139 | GET /compactDBFile HTTP/1.1
|
140 | Host: 127.0.0.1:8081
|
141 |
|
142 | It will return:
|
143 |
|
144 | OK
|
145 |
|
146 |
|
147 | # How it works?
|
148 |
|
149 | It simply executes all your js code to manipulate a `doc` object, and append each
|
150 | js code to a file. Each time when you start up the JDB, it executes all the code in the file,
|
151 | and the last time's `doc` object will come back again in the memory.
|
152 |
|
153 | ****************************************************************************
|
154 |
|
155 | # API
|
156 |
|
157 | The main api of class Jdb.
|
158 |
|
159 | ## `constructor ([options])`
|
160 |
|
161 | * **options**
|
162 |
|
163 | * **dbPath** _{Boolean}_
|
164 |
|
165 | Where to save the database file. Default value is `jdb.db`.
|
166 |
|
167 | * **compactDBFile** _{Boolean}_
|
168 |
|
169 | Whether to compact db file before start up or not. Default true.
|
170 |
|
171 | * **promise** _{Boolean}_
|
172 |
|
173 | Whether to enable promise or not. Default true.
|
174 |
|
175 | * **error** _{Function}_
|
176 |
|
177 | The error handler when initializing database.
|
178 |
|
179 | ## `doc`
|
180 |
|
181 | The main storage object. Readonly. Do not write its property directly.
|
182 |
|
183 | ## `exec ([data], command, [callback])`
|
184 | ## `exec (options)`
|
185 |
|
186 | A api and the only api to interact with the data in database.
|
187 |
|
188 | * **data** _{Object}_
|
189 |
|
190 | `data` should be serializable object. It will be send with `command`, see the `command (jdb)` part.
|
191 |
|
192 | * **command (jdb)** _{Function}_
|
193 |
|
194 | A function or corresponding source code.
|
195 | The code in this function is in another scope (database file scope).
|
196 | Do not share outer variable within it, see the wrong example in quick start part.
|
197 |
|
198 | * **jdb** _{Object}_
|
199 |
|
200 | An object from which you access the functions of the database. Here's the list of its members.
|
201 |
|
202 | * **jdb.data** _{Object}_
|
203 |
|
204 | The `data` object that is sent from the `exec (options)`.
|
205 |
|
206 | * **jdb.doc** _{Object}_
|
207 |
|
208 | The main storage object.
|
209 |
|
210 | * **jdb.save ([data])** _{Function}_
|
211 |
|
212 | When your data manipulation is done, call this method to permanent your change. It will automatically call the send for you.
|
213 |
|
214 | * **data** _{Object}_
|
215 |
|
216 | The same as the `data` of `jdb.send`.
|
217 |
|
218 | * **jdb.send ([data])** _{Function}_
|
219 |
|
220 | Send data to the `callback`.
|
221 |
|
222 | * **data** _{Object}_
|
223 |
|
224 | Type is `Object`. It should be serializable.
|
225 |
|
226 | * **jdb.rollback()** _{Function}_
|
227 |
|
228 | Call it when you want to rollback the change that you made.
|
229 |
|
230 | * **callback (err, data)** _{Function}_
|
231 |
|
232 | This function will be invoked after the `save` or `send` is called.
|
233 |
|
234 | * **err** _{Object}_
|
235 |
|
236 | It can only catch sync errors, you should handle async errors by yourself.
|
237 |
|
238 | * **data** _{Function}_
|
239 |
|
240 | The data you send from `jdb.send(data)` or `jdb.save(data)`.
|
241 |
|
242 |
|
243 | ## `compactDBFile ()`
|
244 |
|
245 | Returns a promise. Reduce the size of the database file. It will calculate all the commands and save the final `doc` object to the file and delete all the other commands.
|
246 |
|
247 | ## `compactDBFileSync ()`
|
248 |
|
249 | The sync version of `compactDBFile (callback)`.
|
250 |
|
251 | ****************************************************************************
|
252 |
|
253 | # Unit test
|
254 |
|
255 | To use `cake`, install [coffee-script](coffeescript.org) globally: `npm install -g coffee-script`.
|
256 |
|
257 | Unit test will test all the basic functions of JDB. Before your pull request, run it first.
|
258 |
|
259 | cake test
|
260 |
|
261 |
|
262 | # Benchmarks
|
263 |
|
264 | To run the benchmark:
|
265 |
|
266 | cake benchmark
|
267 |
|
268 | ### JDB on Intel Core i7 2.3GHz SSD
|
269 |
|
270 | * insert x 15,562 ops/sec ±4.37% (62 runs sampled)
|
271 | * query x 665,237 ops/sec ±0.83% (95 runs sampled)
|
272 |
|
273 | ### MongoDB on Intel Core i7 2.3GHz SSD
|
274 |
|
275 | **JDB is much faster than MongoDB**
|
276 |
|
277 | * insert x 3,744 ops/sec ±2.63% (76 runs sampled)
|
278 | * query x 2,416 ops/sec ±3.89% (70 runs sampled)
|
279 |
|
280 | ### Redis on Intel Core i7 2.3GHz SSD
|
281 |
|
282 | **JDB's query performance is faster than Redis**
|
283 |
|
284 | * insert x 10,619 ops/sec ±2.33% (77 runs sampled)
|
285 | * query x 10,722 ops/sec ±2.27% (80 runs sampled)
|
286 |
|
287 | ### JDB on Digitalocean VPS 1 CPU
|
288 |
|
289 | **Even on a much slower machine JDB is still much faster than MongoDB**
|
290 |
|
291 | * insert x 9,460 ops/sec ±3.34% (78 runs sampled)
|
292 | * query x 343,502 ops/sec ±2.57% (93 runs sampled)
|
293 |
|
294 | ### JDB http server on Intel Core i7 2.3GHz SSD
|
295 |
|
296 | * exec x 65,912 ops/sec ±2.84% (72 runs sampled)
|
297 |
|
298 | Though for MongoDB and Redis, most of their CPU time is ate by their DB adapters, but I think
|
299 | for some small projects, such as personal blog, or a non-cluster application, the adapter issue
|
300 | should also be taken into consideration.
|
301 |
|
302 | # Road Map
|
303 |
|
304 | * More fault tolerance support. Such as file system error handling.
|
305 |
|
306 | * Maybe simple cluster support.
|
307 |
|
308 | # License
|
309 |
|
310 | ### BSD
|
311 |
|
312 | May 2014, Yad Smood
|