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

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 onyl 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)
})