1 | # Lowdb
|
2 |
|
3 | [![](http://img.shields.io/npm/dm/lowdb.svg?style=flat)](https://www.npmjs.org/package/lowdb) [![NPM version](https://badge.fury.io/js/lowdb.svg)](http://badge.fury.io/js/lowdb) [![Build Status](https://travis-ci.org/typicode/lowdb.svg?branch=master)](https://travis-ci.org/typicode/lowdb) [![Donate](https://img.shields.io/badge/patreon-donate-ff69b4.svg)](https://www.patreon.com/typicode)
|
4 |
|
5 | > Small JSON database for Node, Electron and the browser. Powered by Lodash. :zap:
|
6 |
|
7 | ```js
|
8 | db.get('posts')
|
9 | .push({ id: 1, title: 'lowdb is awesome'})
|
10 | .write()
|
11 | ```
|
12 |
|
13 | ## Usage
|
14 |
|
15 | ```sh
|
16 | npm install lowdb
|
17 | ```
|
18 |
|
19 | ```js
|
20 | const low = require('lowdb')
|
21 | const FileSync = require('lowdb/adapters/FileSync')
|
22 |
|
23 | const adapter = new FileSync('db.json')
|
24 | const db = low(adapter)
|
25 |
|
26 | // Set some defaults
|
27 | db.defaults({ posts: [], user: {} })
|
28 | .write()
|
29 |
|
30 | // Add a post
|
31 | db.get('posts')
|
32 | .push({ id: 1, title: 'lowdb is awesome'})
|
33 | .write()
|
34 |
|
35 | // Set a user using Lodash shorthand syntax
|
36 | db.set('user.name', 'typicode')
|
37 | .write()
|
38 | ```
|
39 |
|
40 | Data is saved to `db.json`
|
41 |
|
42 | ```json
|
43 | {
|
44 | "posts": [
|
45 | { "id": 1, "title": "lowdb is awesome"}
|
46 | ],
|
47 | "user": {
|
48 | "name": "typicode"
|
49 | }
|
50 | }
|
51 | ```
|
52 |
|
53 | You can use any [lodash](https://lodash.com/docs) function like [`_.get`](https://lodash.com/docs#get) and [`_.find`](https://lodash.com/docs#find) with shorthand syntax.
|
54 |
|
55 | ```js
|
56 | // Use .value() instead of .write() if you're only reading from db
|
57 | db.get('posts')
|
58 | .find({ id: 1 })
|
59 | .value()
|
60 | ```
|
61 |
|
62 | Lowdb is perfect for CLIs, small servers, Electron apps and npm packages in general.
|
63 |
|
64 | It supports __Node__, the __browser__ and uses __lodash API__, so it's very simple to learn. Actually, if you know Lodash, you already know how to use lowdb :wink:
|
65 |
|
66 | * [Usage examples](https://github.com/typicode/lowdb/tree/master/examples)
|
67 | * [CLI](https://github.com/typicode/lowdb/tree/master/examples#cli)
|
68 | * [Browser](https://github.com/typicode/lowdb/tree/master/examples#browser)
|
69 | * [Server](https://github.com/typicode/lowdb/tree/master/examples#server)
|
70 | * [In-memory](https://github.com/typicode/lowdb/tree/master/examples#in-memory)
|
71 | * [JSFiddle live example](https://jsfiddle.net/typicode/4kd7xxbu/)
|
72 |
|
73 | __Important__ lowdb doesn't support Cluster and may have issues with very large JSON files (~200MB).
|
74 |
|
75 | ## Install
|
76 |
|
77 | ```sh
|
78 | npm install lowdb
|
79 | ```
|
80 |
|
81 | Alternatively, if you're using [yarn](https://yarnpkg.com/)
|
82 |
|
83 | ```sh
|
84 | yarn add lowdb
|
85 | ```
|
86 |
|
87 | A UMD build is also available on [unpkg](https://unpkg.com/) for testing and quick prototyping:
|
88 |
|
89 | ```html
|
90 | <script src="https://unpkg.com/lodash@4/lodash.min.js"></script>
|
91 | <script src="https://unpkg.com/lowdb@0.17/dist/low.min.js"></script>
|
92 | <script src="https://unpkg.com/lowdb@0.17/dist/LocalStorage.min.js"></script>
|
93 | <script>
|
94 | var adapter = new LocalStorage('db')
|
95 | var db = low(adapter)
|
96 | </script>
|
97 | ```
|
98 |
|
99 | ## API
|
100 |
|
101 | __low(adapter)__
|
102 |
|
103 | Returns a lodash [chain](https://lodash.com/docs/4.17.4#chain) with additional properties and functions described below.
|
104 |
|
105 | __db.[...].write()__
|
106 |
|
107 | __db.[...].value()__
|
108 |
|
109 | `write()` is syntactic sugar for calling `value()` and `db.write()` in one line.
|
110 |
|
111 | On the other hand, `value()` is just [\_.protoype.value()](https://lodash.com/docs/4.17.4#prototype-value) and should be used to execute a chain that doesn't change database state.
|
112 |
|
113 |
|
114 | ```js
|
115 | db.set('user.name', 'typicode')
|
116 | .write()
|
117 |
|
118 | // is equivalent to
|
119 | db.set('user.name', 'typicode')
|
120 | .value()
|
121 |
|
122 | db.write()
|
123 | ```
|
124 |
|
125 | __db.___
|
126 |
|
127 | Database lodash instance. Use it to add your own utility functions or third-party mixins like [underscore-contrib](https://github.com/documentcloud/underscore-contrib) or [lodash-id](https://github.com/typicode/lodash-id).
|
128 |
|
129 | ```js
|
130 | db._.mixin({
|
131 | second: function(array) {
|
132 | return array[1]
|
133 | }
|
134 | })
|
135 |
|
136 | db.get('posts')
|
137 | .second()
|
138 | .value()
|
139 | ```
|
140 |
|
141 | __db.getState()__
|
142 |
|
143 | Returns database state.
|
144 |
|
145 | ```js
|
146 | db.getState() // { posts: [ ... ] }
|
147 | ```
|
148 |
|
149 | __db.setState(newState)__
|
150 |
|
151 | Replaces database state.
|
152 |
|
153 | ```js
|
154 | const newState = {}
|
155 | db.setState(newState)
|
156 | ```
|
157 |
|
158 | __db.write()__
|
159 |
|
160 | Persists database using `adapter.write` (depending on the adapter, may return a promise).
|
161 |
|
162 | ```js
|
163 | // With lowdb/adapters/FileSync
|
164 | db.write()
|
165 | console.log('State has been saved')
|
166 |
|
167 | // With lowdb/adapters/FileAsync
|
168 | db.write()
|
169 | .then(() => console.log('State has been saved'))
|
170 | ```
|
171 |
|
172 | __db.read()__
|
173 |
|
174 | Reads source using `storage.read` option (depending on the adapter, may return a promise).
|
175 |
|
176 | ```js
|
177 | // With lowdb/FileSync
|
178 | db.read()
|
179 | console.log('State has been updated')
|
180 |
|
181 | // With lowdb/FileAsync
|
182 | db.write()
|
183 | .then(() => console.log('State has been updated'))
|
184 | ```
|
185 |
|
186 | ## Adapters API
|
187 |
|
188 | Please note this only applies to adapters bundled with Lowdb. Third-party adapters may have different options.
|
189 |
|
190 | For convenience, `FileSync`, `FileAsync` and `LocalBrowser` accept the following options:
|
191 |
|
192 | * __defaultValue__ if file doesn't exist, this value will be used to set the initial state (default: `{}`)
|
193 | * __serialize/deserialize__ functions used before writing and after reading (default: `JSON.stringify` and `JSON.parse`)
|
194 |
|
195 | ```js
|
196 | const adapter = new FileSync('array.yaml', {
|
197 | defaultValue: [],
|
198 | serialize: (array) => toYamlString(array),
|
199 | deserialize: (string) => fromYamlString(string)
|
200 | })
|
201 | ```
|
202 |
|
203 | ## Guide
|
204 |
|
205 | ### How to query
|
206 |
|
207 | With lowdb, you get access to the entire [lodash API](http://lodash.com/), so there are many ways to query and manipulate data. Here are a few examples to get you started.
|
208 |
|
209 | Please note that data is returned by reference, this means that modifications to returned objects may change the database. To avoid such behaviour, you need to use `.cloneDeep()`.
|
210 |
|
211 | Also, the execution of methods is lazy, that is, execution is deferred until `.value()` or `.write()` is called.
|
212 |
|
213 | #### Examples
|
214 |
|
215 | Check if posts exists.
|
216 |
|
217 | ```js
|
218 | db.has('posts')
|
219 | .value()
|
220 | ```
|
221 |
|
222 | Set posts.
|
223 |
|
224 | ```js
|
225 | db.set('posts', [])
|
226 | .write()
|
227 | ```
|
228 |
|
229 |
|
230 | Sort the top five posts.
|
231 |
|
232 | ```js
|
233 | db.get('posts')
|
234 | .filter({published: true})
|
235 | .sortBy('views')
|
236 | .take(5)
|
237 | .value()
|
238 | ```
|
239 |
|
240 | Get post titles.
|
241 |
|
242 | ```js
|
243 | db.get('posts')
|
244 | .map('title')
|
245 | .value()
|
246 | ```
|
247 |
|
248 | Get the number of posts.
|
249 |
|
250 | ```js
|
251 | db.get('posts')
|
252 | .size()
|
253 | .value()
|
254 | ```
|
255 |
|
256 | Get the title of first post using a path.
|
257 |
|
258 | ```js
|
259 | db.get('posts[0].title')
|
260 | .value()
|
261 | ```
|
262 |
|
263 | Update a post.
|
264 |
|
265 | ```js
|
266 | db.get('posts')
|
267 | .find({ title: 'low!' })
|
268 | .assign({ title: 'hi!'})
|
269 | .write()
|
270 | ```
|
271 |
|
272 | Remove posts.
|
273 |
|
274 | ```js
|
275 | db.get('posts')
|
276 | .remove({ title: 'low!' })
|
277 | .write()
|
278 | ```
|
279 |
|
280 | Remove a property.
|
281 |
|
282 | ```js
|
283 | db.unset('user.name')
|
284 | .write()
|
285 | ```
|
286 |
|
287 | Make a deep clone of posts.
|
288 |
|
289 | ```js
|
290 | db.get('posts')
|
291 | .cloneDeep()
|
292 | .value()
|
293 | ```
|
294 |
|
295 | ### How to use id based resources
|
296 |
|
297 | Being able to get data using an id can be quite useful, particularly in servers. To add id-based resources support to lowdb, you have 2 options.
|
298 |
|
299 | [shortid](https://github.com/dylang/shortid) is more minimalist and returns a unique id that you can use when creating resources.
|
300 |
|
301 | ```js
|
302 | const shortid = require('shortid')
|
303 |
|
304 | const postId = db
|
305 | .get('posts')
|
306 | .push({ id: shortid.generate(), title: 'low!' })
|
307 | .write()
|
308 | .id
|
309 |
|
310 | const post = db
|
311 | .get('posts')
|
312 | .find({ id: postId })
|
313 | .value()
|
314 | ```
|
315 |
|
316 | [lodash-id](https://github.com/typicode/lodash-id) provides a set of helpers for creating and manipulating id-based resources.
|
317 |
|
318 | ```js
|
319 | const lodashId = require('lodash-id')
|
320 | const db = low('db.json')
|
321 |
|
322 | db._.mixin(lodashId)
|
323 |
|
324 | const post = db
|
325 | .get('posts')
|
326 | .insert({ title: 'low!' })
|
327 | .write()
|
328 |
|
329 | const post = db
|
330 | .get('posts')
|
331 | .getById(post.id)
|
332 | .value()
|
333 | ```
|
334 |
|
335 | ### How to create custom adapters
|
336 |
|
337 | `low()` accepts custom Adapter, so you can virtually save your data to any storage using any format.
|
338 |
|
339 | ```js
|
340 | class MyStorage {
|
341 | constructor() {
|
342 | // ...
|
343 | }
|
344 |
|
345 | read() {
|
346 | // Should return data (object or array) or a Promise
|
347 | }
|
348 |
|
349 | write(data) {
|
350 | // Should return nothing or a Promise
|
351 | }
|
352 | }
|
353 |
|
354 | const adapter = new MyStorage(args)
|
355 | const db = low()
|
356 | ```
|
357 |
|
358 | See [src/adapters](src/adapters) for examples.
|
359 |
|
360 | ### How to encrypt data
|
361 |
|
362 | `FileSync`, `FileAsync` and `LocalStorage` accept custom `serialize` and `deserialize` functions. You can use them to add encryption logic.
|
363 |
|
364 | ```js
|
365 | const adapter = new FileSync('db.json', {
|
366 | serialize: (data) => encrypt(JSON.stringify(data))
|
367 | deserialize: (data) => JSON.parse(decrypt(data))
|
368 | })
|
369 | ```
|
370 |
|
371 | ## Changelog
|
372 |
|
373 | See changes for each version in the [release notes](https://github.com/typicode/lowdb/releases).
|
374 |
|
375 | ## Limits
|
376 |
|
377 | Lowdb is a convenient method for storing data without setting up a database server. It is fast enough and safe to be used as an embedded database.
|
378 |
|
379 | However, if you seek high performance and scalability more than simplicity, you should probably stick to traditional databases like MongoDB.
|
380 |
|
381 | ## License
|
382 |
|
383 | MIT - [Typicode :cactus:](https://github.com/typicode)
|