How to get range of keys in Leveldb and how gt and lt works

Kevin Simper
Feb 4, 2018 · 2 min read

LevelDB is really easy to use in node.js and it is perfect to start at project with. You can store objects easily with level and then give them a key that looks like storing them in tables with a unique id as name.

user:kevin
user:sofie
user:mike
todos:1
todos:2
todos:3

Then say you want to get all the users, you would use the db.createReadStream() that takes a object where you can give it two properties.

db.createReadStream({
gte: 'user'
lte: 'user'
}).on(‘data’, function(data) {
console.log(data.key)
})

But doing this above would not give you all the users, the reason is that leveldb does a one by one character comparison and the character is converted to ascii code and compared.

That means for the first one u is compared to the first letter of user:kevin and also compared with the lte which stands for less than or equal. The problem is not with gte because the k in kevin is greater than the empty characters.

‘user’ <= ‘user:kevin’
true

the problem arises when doing the lte, where it becomes false

‘user:kevin’ <= ‘user’
false

and that makes it not return that key in the readstream. We have to have the key be greater than what is is compared to. JulianGruber wrote a npm package which does something really simple and appends “~” to the string that goes to lte

db.createReadStream({
gte: 'user'
lte: 'user~'
})

and the reason that works is that the charCode of “~” with is code 126 and that is bigger than z which has the code 122.

‘~’.charCodeAt(0)
126
‘z’.charCodeAt(0)
122

that is a really cool idea until you get a charCode that is higher than 126 and danish chars like æøå are a lot higher than 126.

‘ø’.charCodeAt(0)
248

So to solve that problem, the best solution would be to shift the first letter in the lte by one, so it would look something like this

const key = 'user:'
db.createReadStream({
gte: key,
lte: String.fromCharCode(key.charCodeAt(0) + 1)
})

This would only return “v” for the lte and it would be true for a key like user:åben

Conclusion

I defenitly learned something about how javascript compares strings and how leveldb works. I hope it gave you a solution on how to quickly iterate and get the keys that you want.

const key = 'user:'
db.createReadStream({
gte: key,
lte: String.fromCharCode(key.charCodeAt(0) + 1)
})

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store