Range Scans
Learn how to scan and seek over ranges of keys in SlateDB
SlateDB stores key-value pairs sorted by key in lexicographic byte order. A range scan creates an iterator over that sorted keyspace, so you can read a bounded slice, read every entry, or jump forward within an iterator.
Scan all entries
Section titled “Scan all entries”Use Db::scan(..) to iterate over the full keyspace. Range scans follow bytewise key order, so test_key10 sorts before test_key2. If numeric order matters, use fixed-width encodings such as test_key02 and test_key10.
let mut entries = db.scan::<Vec<u8>, _>(..).await?;while let Some(kv) = entries.next().await? { println!("{:?} = {:?}", kv.key, kv.value);}Choose range bounds
Section titled “Choose range bounds”Pass a Rust range to scan when you know the keys you want. A bounded range like "test_key2".."test_key4" includes the start bound and excludes the end bound.
db.scan("test_key2".."test_key4").await?; // excludes test_key4db.scan("test_key2"..="test_key4").await?; // includes test_key4db.scan("test_key2"..).await?; // test_key2 and laterdb.scan(.."test_key4").await?; // before test_key4db.scan::<Vec<u8>, _>(..).await?; // all keysSeek within a scan
Section titled “Seek within a scan”Call seek on an iterator to fast-forward to the first key equal to or greater than the requested key. The seek target must stay inside the original scan range and must move forward from the iterator’s current position.
let mut iter = db.scan::<Vec<u8>, _>(..).await?;iter.seek(b"test_key3").await?;let kv = iter.next().await?.unwrap();assert_eq!(kv.key.as_ref(), b"test_key3");Scan for prefixes
Section titled “Scan for prefixes”If your access pattern is “all keys that start with this prefix,” use scan_prefix instead of manually building a start and end range.
let mut iter = db.scan_prefix(b"test_key").await?;Complete example
Section titled “Complete example”use slatedb::object_store::memory::InMemory;use slatedb::{Db, Error};use std::sync::Arc;
#[tokio::main]async fn main() -> Result<(), Error> { let object_store = Arc::new(InMemory::new()); let db = Db::open("/tmp/slatedb_range_scans", object_store).await?;
db.put(b"test_key1", b"test_value1").await?; db.put(b"test_key2", b"test_value2").await?; db.put(b"test_key3", b"test_value3").await?; db.put(b"test_key4", b"test_value4").await?; db.put(b"test_key10", b"test_value10").await?;
// Scan over unbound range let mut iter = db.scan::<Vec<u8>, _>(..).await?; // Scans return bytewise key order let expected = [ ("test_key1", "test_value1"), ("test_key10", "test_value10"), ("test_key2", "test_value2"), ("test_key3", "test_value3"), ("test_key4", "test_value4"), ]; for (expected_key, expected_value) in expected { let entry = iter.next().await?.unwrap(); assert_eq!(entry.key.as_ref(), expected_key.as_bytes()); assert_eq!(entry.value.as_ref(), expected_value.as_bytes()); } assert_eq!(iter.next().await?, None);
// Scan over bound range let mut iter = db.scan("test_key2"..="test_key3").await?; let kv2 = iter.next().await?.unwrap(); assert_eq!(kv2.key, b"test_key2".as_slice()); assert_eq!(kv2.value, b"test_value2".as_slice());
let kv3 = iter.next().await?.unwrap(); assert_eq!(kv3.key, b"test_key3".as_slice()); assert_eq!(kv3.value, b"test_value3".as_slice()); assert_eq!(iter.next().await?, None);
// Seek ahead to next key let mut iter = db.scan::<Vec<u8>, _>(..).await?; let next_key = b"test_key4"; iter.seek(next_key).await?; let kv4 = iter.next().await?.unwrap(); assert_eq!(kv4.key, b"test_key4".as_slice()); assert_eq!(kv4.value, b"test_value4".as_slice()); assert_eq!(iter.next().await?, None);
// Scan over prefix let mut prefixed = db.scan_prefix(b"test_key1").await?; let expected_keys: [&[u8]; 2] = [b"test_key1", b"test_key10"]; for expected_key in expected_keys { let kv = prefixed.next().await?.unwrap(); assert_eq!(kv.key.as_ref(), expected_key); } assert_eq!(prefixed.next().await?, None);
db.close().await?;
Ok(())}