Skip to content

Commit cde5433

Browse files
author
James Halliday
committed
good enough
1 parent a754a2d commit cde5433

File tree

1 file changed

+201
-5
lines changed

1 file changed

+201
-5
lines changed

leveldb.markdown

+201-5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ var db = level('./whatever.db');
5353
---
5454
# put
5555

56+
set a value for a key with `.put()`
57+
5658
``` js
5759
var level = require('level');
5860
var db = level('./whatever.db');
@@ -64,6 +66,8 @@ db.put('key', 'value', function (err) {
6466
---
6567
# get
6668

69+
load a value for a key with `.get()`
70+
6771
``` js
6872
var level = require('level');
6973
var db = level('./whatever.db');
@@ -76,9 +80,30 @@ db.get('key', function (err, value) {
7680
---
7781
# del
7882

83+
delete a value at a key with `.del()`:
84+
85+
---
86+
# atomicity
87+
88+
either all transactions succeed
89+
or all transactions fail
90+
91+
---
92+
# consistency
93+
94+
atomicity is important to enforce consistency
95+
96+
Suppose a user has just signed up.
97+
We might need to create:
98+
99+
* a record for their
100+
* a record for their login username and password
101+
79102
---
80103
# batch
81104

105+
perform multiple
106+
82107
``` js
83108
```
84109

@@ -88,25 +113,196 @@ db.get('key', function (err, value) {
88113
---
89114
# thinking lexicographically
90115

116+
keys are sorted by their string values:
117+
118+
* aaaaa
119+
* bb
120+
* ccccc
121+
122+
---
123+
# numbers get converted into strings!
124+
125+
* "1"
126+
* "12"
127+
* "3"
128+
* "4"
129+
* "555"
130+
* "6"
131+
132+
---
133+
# bytewise
134+
135+
a nicer way of handling lexicographic values
136+
137+
sorting for numbers happens as you might expect:
138+
139+
* 1
140+
* 3
141+
* 4
142+
* 6
143+
* 12
144+
* 555
145+
146+
---
147+
# bytewise hierarchy
148+
149+
and there is also a hierarchy of types.
150+
`null` is the first type to sort and `undefined` is the
151+
last.
152+
153+
* null
154+
* numbers
155+
* strings
156+
* arrays
157+
* objects
158+
* undefined
159+
160+
---
161+
# bytewise
162+
163+
Arrays are sorted component-wise, which means we can make
164+
keys like:
165+
166+
[ 'user', 'substack' ]
167+
168+
and then to query all users we can do:
169+
170+
``` js
171+
db.createReadStream({
172+
gt: [ 'user', null ],
173+
lt: [ 'user', undefined ]
174+
})
175+
```
176+
91177
---
92178
# organizing your keys
93179

180+
key/value structure we might use for
181+
a user/post system:
182+
183+
``` json
184+
[{"key":"user!substack","value":{"bio":"beep boop"}},
185+
{"key":"user!maxogden","value":{"bio":"cats."}},
186+
{"key":"post!substack!2015-01-04 11:45","value":"cool beans"}]
187+
{"key":"post!maxogden!2015-01-03 17:33","value":"soup."}]
188+
```
189+
190+
---
191+
192+
This will let us efficiently query for a user's posts:
193+
194+
``` js
195+
db.createReadStream({
196+
gt: "user!substack",
197+
lt: "user!substack!~"
198+
})
199+
```
200+
201+
---
202+
# organizing keys with bytewise
203+
204+
or with bytewise:
205+
206+
``` json
207+
[{"key":["user","substack"],"value":{"bio":"beep boop"}},
208+
{"key":["user","maxogden"],"value":{"bio":"cats."}},
209+
{"key":["post","substack","2015-01-04 11:45"],"value":"cool beans"}]
210+
{"key":["post","maxogden","2015-01-03 17:33"],"value":"soup."}]
211+
```
212+
213+
---
214+
# and querying with bytewise:
215+
216+
``` js
217+
db.createReadStream({
218+
gt: ["user","substack",null],
219+
lt: ["user","substack",undefined]
220+
})
221+
```
222+
223+
---
224+
225+
In either case,
226+
what if we want to get ALL the posts on the system?
227+
94228
---
95229
# secondary indexes
96230

231+
We can use `.batch()` to create multiple keys for each post:
232+
233+
``` js
234+
var now = new Date().toISOString();
235+
var id = crypto.randomBytes(16).toString('hex');
236+
var subkey = now + '!' + id;
237+
db.batch([
238+
{type:'post',key:'post!substack!'+subkey,value:msg},
239+
{type:'post',key:'post!'+subkey,value:msg},
240+
]);
241+
```
242+
97243
---
98-
# bytewise
244+
# querying our indexes
245+
246+
now to get all the posts system-wide sorted by date,
247+
we can do:
248+
249+
``` js
250+
db.createReadStream({
251+
start: "post!",
252+
end: "post!~"
253+
})
254+
```
99255

100256
---
101257
# subleveldown
102258

259+
we can create nested sub-databases with subleveldown:
260+
261+
``` js
262+
var level = require('level');
263+
var sublevel = require('subleveldown');
264+
var db = level('whatever.db');
265+
266+
var catsdb = sublevel(db, 'cats');
267+
var robodb = sublevel(db, 'robots');
268+
269+
catsdb.put('msg', 'meow');
270+
robodb.put('msg', 'beep boop');
271+
```
272+
273+
and `catsdb` and `robodb` will each key a unique namespace
274+
for a `msg` key.
275+
103276
---
104277
# modularity
105278

106-
* accountdown
107-
* subleveldown
108-
* cookie-auth
279+
Instead of building in a lot of features, in leveldb you can
280+
use npm to install packages:
281+
282+
* [subleveldown](https://npmjs.org/package/subleveldown)
283+
* [cookie-auth](https://npmjs.org/package/cookie-auth)
284+
* [accountdown](https://npmjs.org/package/accountdown)
285+
* [forkdb](https://npmjs.org/package/forkdb)
286+
287+
---
288+
# accountdown
289+
290+
Making user accounts is actually surprisingly tricky!
291+
292+
You've got to remember:
293+
294+
* only create a user if the name hasn't been taken
295+
* hash passwords with a unique salt for each user
296+
* lock records to prevent account creation race conditions
297+
* extensibility points for more login methods in the future
298+
299+
---
300+
# links
301+
302+
* [levelup docs](https://github.com/rvagg/node-levelup)
303+
* [example leveldb website with accountdown](https://github.com/substack/example-user-website)
109304

110305
---
111-
#
306+
# homework
112307

308+
http://nodeschool.io/#levelmeup

0 commit comments

Comments
 (0)