Level / level

Universal abstract-level database for Node.js and browsers.
MIT License
1.55k stars 106 forks source link

how to get all sublevel db #238

Open williamnie opened 1 year ago

williamnie commented 1 year ago

I want to directly retrieve all sublevels through the Level API, but I couldn't find any relevant APIs. Instead of using a method that involves reading all keys and looping through them to check if they contain certain characters, I think it would be more efficient to store a small index when creating the sublevel.

fedd commented 11 months ago

I'm seconding this question.

In a relational database we would group by a part of a compound key to see if a category of entries is present.

sublevel key value ========================= example 19 [object] example 20 [object] another a [object]

select sublevel from kvstore group by sublevel This can still fully scan the table, but can also try to get the index stats instead select sublevel, count(*) from kvstore group by sublevel

In a key-value db when we concatenate category into a key, it would be nice if the sublevels are tracked somehow

key value ======================= !example!19 [object] !example!20 [object] !another!a [object]

How do we get all of the existing sublevels?

vweevers commented 8 months ago

You can use the database itself as an index and query it with a skip scan to discover sublevels. Roughly like so (not fully tested):

const { AbstractSublevel } = require('abstract-level')

// Discover sublevels using a skip scan
async function sublevels (db, options) {
  const separator = AbstractSublevel.defaults(options).separator
  const upperBound = String.fromCharCode(separator.charCodeAt(0) + 1)
  const iterator = db.keys({ keyEncoding: 'utf8' })
  const names = []

  try {
    let target = separator

    while (true) {
      iterator.seek(target)
      const key = await iterator.next()

      // Stop if no sublevel prefix is found
      if (key === undefined || key[0] !== separator) {
        break
      }

      // Check if key has a complete sublevel prefix, e.g. '!a!'
      const i = key.indexOf(separator, 1)
      if (i === -1) break

      // Extract name, e.g. 'a'
      const name = key.slice(1, i)
      names.push(name)

      // Seek to next sublevel that follows '!a"'
      target = separator + name + upperBound
    }
  } finally {
    await iterator.close()
  }

  return names
}