UNPKG

20.7 kBMarkdownView Raw
1# levelup
2
3[![level badge][level-badge]](https://github.com/level/awesome)
4[![npm](https://img.shields.io/npm/v/levelup.svg)](https://www.npmjs.com/package/levelup)
5![Node version](https://img.shields.io/node/v/levelup.svg)
6[![Build Status](https://secure.travis-ci.org/Level/levelup.svg?branch=master)](http://travis-ci.org/Level/levelup)
7[![david](https://david-dm.org/Level/levelup.svg)](https://david-dm.org/level/levelup)
8[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
9[![npm](https://img.shields.io/npm/dm/levelup.svg)](https://www.npmjs.com/package/levelup)
10
11 * [Introduction](#introduction)
12 * [Supported Platforms](#supported-platforms)
13 * [Usage](#usage)
14 * [API](#api)
15 * [Promise Support](#promise-support)
16 * [Events](#events)
17 * [Extending](#extending)
18 * [Multi-process Access](#multi-process-access)
19 * [Support](#support)
20 * [Contributing](#contributing)
21 * [License](#license)
22
23**If you are upgrading:** please see [`UPGRADING.md`](UPGRADING.md).
24
25## Introduction
26
27**Fast and simple storage. A Node.js wrapper for `abstract-leveldown` compliant stores, which follow the characteristics of [LevelDB](https://github.com/google/leveldb).**
28
29LevelDB is a simple key-value store built by Google. It's used in Google Chrome and many other products. LevelDB supports arbitrary byte arrays as both keys and values, singular *get*, *put* and *delete* operations, *batched put and delete*, bi-directional iterators and simple compression using the very fast [Snappy](http://google.github.io/snappy/) algorithm.
30
31LevelDB stores entries sorted lexicographically by keys. This makes the [streaming interface](#createReadStream) of `levelup` - which exposes LevelDB iterators as [Readable Streams](https://nodejs.org/docs/latest/api/stream.html#stream_readable_streams) - a very powerful query mechanism.
32
33The most common store is [`leveldown`](https://github.com/level/leveldown/) which provides a pure C++ binding to LevelDB. [Many alternative stores are available](https://github.com/Level/awesome/#stores) such as [`level.js`](https://github.com/level/level.js) in the browser or [`memdown`](https://github.com/level/memdown) for an in-memory store. They typically support strings and Buffers for both keys and values. For a richer set of data types you can wrap the store with [`encoding-down`](https://github.com/level/encoding-down).
34
35**The [`level`](https://github.com/level/level) package is the recommended way to get started.** It conveniently bundles `levelup`, [`leveldown`](https://github.com/level/leveldown/) and [`encoding-down`](https://github.com/level/encoding-down). Its main export is `levelup` - i.e. you can do `var db = require('level')`.
36
37## Supported Platforms
38
39We aim to support Active LTS and Current Node.js releases as well as browsers. For support of the underlying store, please see the respective documentation.
40
41## Usage
42
43First you need to install `levelup`! No stores are included so you must also install `leveldown` (for example).
44
45```sh
46$ npm install levelup leveldown
47```
48
49All operations are asynchronous. If you do not provide a callback, [a Promise is returned](#promise-support).
50
51```js
52var levelup = require('levelup')
53var leveldown = require('leveldown')
54
55// 1) Create our store
56var db = levelup(leveldown('./mydb'))
57
58// 2) Put a key & value
59db.put('name', 'levelup', function (err) {
60 if (err) return console.log('Ooops!', err) // some kind of I/O error
61
62 // 3) Fetch by key
63 db.get('name', function (err, value) {
64 if (err) return console.log('Ooops!', err) // likely the key was not found
65
66 // Ta da!
67 console.log('name=' + value)
68 })
69})
70```
71
72## API
73
74 * [<code><b>levelup()</b></code>](#ctor)
75 * [<code>db.<b>open()</b></code>](#open)
76 * [<code>db.<b>close()</b></code>](#close)
77 * [<code>db.<b>put()</b></code>](#put)
78 * [<code>db.<b>get()</b></code>](#get)
79 * [<code>db.<b>del()</b></code>](#del)
80 * [<code>db.<b>batch()</b></code> *(array form)*](#batch)
81 * [<code>db.<b>batch()</b></code> *(chained form)*](#batch_chained)
82 * [<code>db.<b>isOpen()</b></code>](#isOpen)
83 * [<code>db.<b>isClosed()</b></code>](#isClosed)
84 * [<code>db.<b>createReadStream()</b></code>](#createReadStream)
85 * [<code>db.<b>createKeyStream()</b></code>](#createKeyStream)
86 * [<code>db.<b>createValueStream()</b></code>](#createValueStream)
87
88### Special Notes
89 * <a href="#writeStreams">What happened to <code><b>db.createWriteStream()</b></code></a>
90
91<a name="ctor"></a>
92### levelup(db[, options[, callback]])
93The main entry point for creating a new `levelup` instance.
94
95- `db` must be an [`abstract-leveldown`](https://github.com/level/abstract-leveldown) compliant store.
96- `options` is passed on to the underlying store when opened and is specific to the type of store being used
97
98Calling `levelup(db)` will also open the underlying store. This is an asynchronous operation which will trigger your callback if you provide one. The callback should take the form `function (err, db) {}` where `db` is the `levelup` instance. If you don't provide a callback, any read & write operations are simply queued internally until the store is fully opened.
99
100This leads to two alternative ways of managing a `levelup` instance:
101
102```js
103levelup(leveldown(location), options, function (err, db) {
104 if (err) throw err
105
106 db.get('foo', function (err, value) {
107 if (err) return console.log('foo does not exist')
108 console.log('got foo =', value)
109 })
110})
111```
112
113Versus the equivalent:
114
115```js
116// Will throw if an error occurs
117var db = levelup(leveldown(location), options)
118
119db.get('foo', function (err, value) {
120 if (err) return console.log('foo does not exist')
121 console.log('got foo =', value)
122})
123```
124
125<a name="open"></a>
126### db.open([callback])
127Opens the underlying store. In general you should never need to call this method directly as it's automatically called by <a href="#ctor"><code>levelup()</code></a>.
128
129However, it is possible to *reopen* the store after it has been closed with <a href="#close"><code>close()</code></a>, although this is not generally advised.
130
131If no callback is passed, a promise is returned.
132
133<a name="close"></a>
134### db.close([callback])
135<code>close()</code> closes the underlying store. The callback will receive any error encountered during closing as the first argument.
136
137You should always clean up your `levelup` instance by calling `close()` when you no longer need it to free up resources. A store cannot be opened by multiple instances of `levelup` simultaneously.
138
139If no callback is passed, a promise is returned.
140
141<a name="put"></a>
142### db.put(key, value[, options][, callback])
143<code>put()</code> is the primary method for inserting data into the store. Both `key` and `value` can be of any type as far as `levelup` is concerned.
144
145`options` is passed on to the underlying store.
146
147If no callback is passed, a promise is returned.
148
149<a name="get"></a>
150### db.get(key[, options][, callback])
151<code>get()</code> is the primary method for fetching data from the store. The `key` can be of any type. If it doesn't exist in the store then the callback or promise will receive an error. A not-found err object will be of type `'NotFoundError'` so you can `err.type == 'NotFoundError'` or you can perform a truthy test on the property `err.notFound`.
152
153```js
154db.get('foo', function (err, value) {
155 if (err) {
156 if (err.notFound) {
157 // handle a 'NotFoundError' here
158 return
159 }
160 // I/O or other error, pass it up the callback chain
161 return callback(err)
162 }
163
164 // .. handle `value` here
165})
166```
167
168`options` is passed on to the underlying store.
169
170If no callback is passed, a promise is returned.
171
172<a name="del"></a>
173### db.del(key[, options][, callback])
174<code>del()</code> is the primary method for removing data from the store.
175```js
176db.del('foo', function (err) {
177 if (err)
178 // handle I/O or other error
179});
180```
181
182`options` is passed on to the underlying store.
183
184If no callback is passed, a promise is returned.
185
186<a name="batch"></a>
187### db.batch(array[, options][, callback]) *(array form)*
188<code>batch()</code> can be used for very fast bulk-write operations (both *put* and *delete*). The `array` argument should contain a list of operations to be executed sequentially, although as a whole they are performed as an atomic operation inside the underlying store.
189
190Each operation is contained in an object having the following properties: `type`, `key`, `value`, where the *type* is either `'put'` or `'del'`. In the case of `'del'` the `value` property is ignored. Any entries with a `key` of `null` or `undefined` will cause an error to be returned on the `callback` and any `type: 'put'` entry with a `value` of `null` or `undefined` will return an error.
191
192If `key` and `value` are defined but `type` is not, it will default to `'put'`.
193
194```js
195var ops = [
196 { type: 'del', key: 'father' },
197 { type: 'put', key: 'name', value: 'Yuri Irsenovich Kim' },
198 { type: 'put', key: 'dob', value: '16 February 1941' },
199 { type: 'put', key: 'spouse', value: 'Kim Young-sook' },
200 { type: 'put', key: 'occupation', value: 'Clown' }
201]
202
203db.batch(ops, function (err) {
204 if (err) return console.log('Ooops!', err)
205 console.log('Great success dear leader!')
206})
207```
208
209`options` is passed on to the underlying store.
210
211If no callback is passed, a promise is returned.
212
213<a name="batch_chained"></a>
214### db.batch() *(chained form)*
215<code>batch()</code>, when called with no arguments will return a `Batch` object which can be used to build, and eventually commit, an atomic batch operation. Depending on how it's used, it is possible to obtain greater performance when using the chained form of `batch()` over the array form.
216
217```js
218db.batch()
219 .del('father')
220 .put('name', 'Yuri Irsenovich Kim')
221 .put('dob', '16 February 1941')
222 .put('spouse', 'Kim Young-sook')
223 .put('occupation', 'Clown')
224 .write(function () { console.log('Done!') })
225```
226
227<b><code>batch.put(key, value)</code></b>
228
229Queue a *put* operation on the current batch, not committed until a `write()` is called on the batch.
230
231This method may `throw` a `WriteError` if there is a problem with your put (such as the `value` being `null` or `undefined`).
232
233<b><code>batch.del(key)</code></b>
234
235Queue a *del* operation on the current batch, not committed until a `write()` is called on the batch.
236
237This method may `throw` a `WriteError` if there is a problem with your delete.
238
239<b><code>batch.clear()</code></b>
240
241Clear all queued operations on the current batch, any previous operations will be discarded.
242
243<b><code>batch.length</code></b>
244
245The number of queued operations on the current batch.
246
247<b><code>batch.write([callback])</code></b>
248
249Commit the queued operations for this batch. All operations not *cleared* will be written to the underlying store atomically, that is, they will either all succeed or fail with no partial commits.
250
251If no callback is passed, a promise is returned.
252
253<a name="isOpen"></a>
254### db.isOpen()
255
256A `levelup` instance can be in one of the following states:
257
258 * *"new"* - newly created, not opened or closed
259 * *"opening"* - waiting for the underlying store to be opened
260 * *"open"* - successfully opened the store, available for use
261 * *"closing"* - waiting for the store to be closed
262 * *"closed"* - store has been successfully closed, should not be used
263
264`isOpen()` will return `true` only when the state is "open".
265
266<a name="isClosed"></a>
267### db.isClosed()
268
269*See <a href="#put"><code>isOpen()</code></a>*
270
271`isClosed()` will return `true` only when the state is "closing" *or* "closed", it can be useful for determining if read and write operations are permissible.
272
273<a name="createReadStream"></a>
274### db.createReadStream([options])
275
276Returns a [Readable Stream](https://nodejs.org/docs/latest/api/stream.html#stream_readable_streams) of key-value pairs. A pair is an object with `key` and `value` properties. By default it will stream all entries in the underlying store from start to end. Use the options described below to control the range, direction and results.
277
278```js
279db.createReadStream()
280 .on('data', function (data) {
281 console.log(data.key, '=', data.value)
282 })
283 .on('error', function (err) {
284 console.log('Oh my!', err)
285 })
286 .on('close', function () {
287 console.log('Stream closed')
288 })
289 .on('end', function () {
290 console.log('Stream ended')
291 })
292```
293
294You can supply an options object as the first parameter to `createReadStream()` with the following properties:
295
296* `gt` (greater than), `gte` (greater than or equal) define the lower bound of the range to be streamed. Only entries where the key is greater than (or equal to) this option will be included in the range. When `reverse=true` the order will be reversed, but the entries streamed will be the same.
297
298* `lt` (less than), `lte` (less than or equal) define the higher bound of the range to be streamed. Only entries where the key is less than (or equal to) this option will be included in the range. When `reverse=true` the order will be reversed, but the entries streamed will be the same.
299
300* `reverse` *(boolean, default: `false`)*: stream entries in reverse order. Beware that due to the way that stores like LevelDB work, a reverse seek can be slower than a forward seek.
301
302* `limit` *(number, default: `-1`)*: limit the number of entries collected by this stream. This number represents a *maximum* number of entries and may not be reached if you get to the end of the range first. A value of `-1` means there is no limit. When `reverse=true` the entries with the highest keys will be returned instead of the lowest keys.
303
304* `keys` *(boolean, default: `true`)*: whether the results should contain keys. If set to `true` and `values` set to `false` then results will simply be keys, rather than objects with a `key` property. Used internally by the `createKeyStream()` method.
305
306* `values` *(boolean, default: `true`)*: whether the results should contain values. If set to `true` and `keys` set to `false` then results will simply be values, rather than objects with a `value` property. Used internally by the `createValueStream()` method.
307
308Legacy options:
309
310* `start`: instead use `gte`
311
312* `end`: instead use `lte`
313
314<a name="createKeyStream"></a>
315### db.createKeyStream([options])
316
317Returns a [Readable Stream](https://nodejs.org/docs/latest/api/stream.html#stream_readable_streams) of keys rather than key-value pairs. Use the same options as described for [`createReadStream`](#createReadStream) to control the range and direction.
318
319You can also obtain this stream by passing an options object to `createReadStream()` with `keys` set to `true` and `values` set to `false`. The result is equivalent; both streams operate in [object mode](https://nodejs.org/docs/latest/api/stream.html#stream_object_mode).
320
321```js
322db.createKeyStream()
323 .on('data', function (data) {
324 console.log('key=', data)
325 })
326
327// same as:
328db.createReadStream({ keys: true, values: false })
329 .on('data', function (data) {
330 console.log('key=', data)
331 })
332```
333
334<a name="createValueStream"></a>
335### db.createValueStream([options])
336
337Returns a [Readable Stream](https://nodejs.org/docs/latest/api/stream.html#stream_readable_streams) of values rather than key-value pairs. Use the same options as described for [`createReadStream`](#createReadStream) to control the range and direction.
338
339You can also obtain this stream by passing an options object to `createReadStream()` with `values` set to `true` and `keys` set to `false`. The result is equivalent; both streams operate in [object mode](https://nodejs.org/docs/latest/api/stream.html#stream_object_mode).
340
341```js
342db.createValueStream()
343 .on('data', function (data) {
344 console.log('value=', data)
345 })
346
347// same as:
348db.createReadStream({ keys: false, values: true })
349 .on('data', function (data) {
350 console.log('value=', data)
351 })
352```
353
354<a name="writeStreams"></a>
355#### What happened to `db.createWriteStream`?
356
357`db.createWriteStream()` has been removed in order to provide a smaller and more maintainable core. It primarily existed to create symmetry with `db.createReadStream()` but through much [discussion](https://github.com/level/levelup/issues/199), removing it was the best course of action.
358
359The main driver for this was performance. While `db.createReadStream()` performs well under most use cases, `db.createWriteStream()` was highly dependent on the application keys and values. Thus we can't provide a standard implementation and encourage more `write-stream` implementations to be created to solve the broad spectrum of use cases.
360
361Check out the implementations that the community has already produced [here](https://github.com/level/levelup/wiki/Modules#write-streams).
362
363## Promise Support
364
365`levelup` ships with native `Promise` support out of the box.
366
367Each function accepting a callback returns a promise if the callback is omitted. This applies for:
368
369- `db.get(key[, options])`
370- `db.put(key, value[, options])`
371- `db.del(key[, options])`
372- `db.batch(ops[, options])`
373- `db.batch().write()`
374
375The only exception is the `levelup` constructor itself, which if no callback is passed will lazily open the underlying store in the background.
376
377Example:
378
379```js
380var db = levelup(leveldown('./my-db'))
381
382db.put('foo', 'bar')
383 .then(function () { return db.get('foo') })
384 .then(function (value) { console.log(value) })
385 .catch(function (err) { console.error(err) })
386```
387
388Or using `async/await`:
389
390```js
391const main = async () => {
392 const db = levelup(leveldown('./my-db'))
393
394 await db.put('foo', 'bar')
395 console.log(await db.get('foo'))
396}
397```
398
399## Events
400
401`levelup` is an [`EventEmitter`](https://nodejs.org/api/events.html) and emits the following events.
402
403| Event | Description | Arguments |
404|:----------|:----------------------------|:---------------------|
405| `put` | Key has been updated | `key, value` (any) |
406| `del` | Key has been deleted | `key` (any) |
407| `batch` | Batch has executed | `operations` (array) |
408| `opening` | Underlying store is opening | - |
409| `open` | Store has opened | - |
410| `ready` | Alias of `open` | - |
411| `closing` | Store is closing | - |
412| `closed` | Store has closed. | - |
413
414For example you can do:
415
416```js
417db.on('put', function (key, value) {
418 console.log('inserted', { key, value })
419})
420```
421
422## Extending
423
424A list of <a href="https://github.com/level/levelup/wiki/Modules"><b>Level modules and projects</b></a> can be found in the wiki. We are in the process of moving all this to [`awesome`](https://github.com/Level/awesome/).
425
426## Multi-process Access
427
428Stores like LevelDB are thread-safe but they are **not** suitable for accessing with multiple processes. You should only ever have a store open from a single Node.js process. Node.js clusters are made up of multiple processes so a `levelup` instance cannot be shared between them either.
429
430See the aformentioned <a href="https://github.com/level/levelup/wiki/Modules"><b>wiki</b></a> for modules like [multilevel](https://github.com/juliangruber/multilevel), that may help if you require a single store to be shared across processes.
431
432## Support
433
434There are multiple ways you can find help in using Level in Node.js:
435
436 * **IRC:** you'll find an active group of `levelup` users in the **##leveldb** channel on Freenode, including most of the contributors to this project.
437 * **Mailing list:** there is an active [Node.js LevelDB](https://groups.google.com/forum/#!forum/node-levelup) Google Group.
438 * **GitHub:** you're welcome to open an issue here on this GitHub repository if you have a question.
439
440## Contributing
441
442`levelup` is an **OPEN Open Source Project**. This means that:
443
444> Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.
445
446See the [contribution guide](https://github.com/Level/community/blob/master/CONTRIBUTING.md) for more details.
447
448## License
449
450Copyright &copy; 2012-2018 `levelup` [contributors](https://github.com/level/community#contributors).
451
452`levelup` is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included `LICENSE.md` file for more details.
453
454*`levelup` builds on the excellent work of the LevelDB and Snappy teams from Google and additional contributors. LevelDB and Snappy are both issued under the [New BSD License](http://opensource.org/licenses/BSD-3-Clause).*
455
456[level-badge]: http://leveldb.org/img/badge.svg