diff --git a/rust-libs/tools/kv_typed/src/backend.rs b/rust-libs/tools/kv_typed/src/backend.rs
index 6cfaa9f10cced54d39918ec55a9a676bb4cb2e2b..bafc69ab76aaed2f173a2ea24db82848ff9ab8aa 100644
--- a/rust-libs/tools/kv_typed/src/backend.rs
+++ b/rust-libs/tools/kv_typed/src/backend.rs
@@ -55,6 +55,7 @@ pub trait BackendCol: 'static + Clone + Debug + Send + Sync {
         f: F,
     ) -> KvResult<Option<D>>;
     fn clear(&mut self) -> KvResult<()>;
+    fn contains_key<K: Key>(&self, k: &K) -> KvResult<bool>;
     fn count(&self) -> KvResult<usize>;
     fn iter<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter;
     fn put<K: Key, V: Value>(&mut self, k: &K, value: &V) -> KvResult<()>;
diff --git a/rust-libs/tools/kv_typed/src/backend/leveldb.rs b/rust-libs/tools/kv_typed/src/backend/leveldb.rs
index d0d710b5c9fc22a8333e25e1b23e626307d14cf5..b03a712223fd9601d051c1a377c7c972deb5bdf9 100644
--- a/rust-libs/tools/kv_typed/src/backend/leveldb.rs
+++ b/rust-libs/tools/kv_typed/src/backend/leveldb.rs
@@ -126,6 +126,10 @@ impl BackendCol for LevelDbCol {
             .count())
     }
     #[inline(always)]
+    fn contains_key<K: Key>(&self, k: &K) -> KvResult<bool> {
+        k.as_bytes(|k_bytes| Ok(self.0.get(ReadOptions::new(), k_bytes)?.is_some()))
+    }
+    #[inline(always)]
     fn get<K: Key, V: Value>(&self, k: &K) -> KvResult<Option<V>> {
         k.as_bytes(|k_bytes| {
             self.0
diff --git a/rust-libs/tools/kv_typed/src/backend/memory.rs b/rust-libs/tools/kv_typed/src/backend/memory.rs
index ccc0124809dd7f35dca0939f79333844b493a914..fd3709c5c59eab6c3b1f59155c34ca701d075525 100644
--- a/rust-libs/tools/kv_typed/src/backend/memory.rs
+++ b/rust-libs/tools/kv_typed/src/backend/memory.rs
@@ -241,6 +241,10 @@ impl BackendCol for MemCol {
         Ok(self.tree.len())
     }
     #[inline(always)]
+    fn contains_key<K: Key>(&self, k: &K) -> KvResult<bool> {
+        k.as_bytes(|k_bytes| Ok(self.tree.contains_key(k_bytes)))
+    }
+    #[inline(always)]
     fn get<K: Key, V: Value>(&self, k: &K) -> KvResult<Option<V>> {
         k.as_bytes(|k_bytes| {
             self.tree
diff --git a/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs
index 2c41ab4f91e9ba0c2862534a420f04c65d28ea12..d77bcedda42b506b4861a5587fec26312038a3ea 100644
--- a/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs
+++ b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs
@@ -81,6 +81,10 @@ impl BackendCol for MemCol {
         }
     }
     #[inline(always)]
+    fn contains_key<K: Key>(&self, _k: &K) -> KvResult<bool> {
+        Ok(self.0.is_some())
+    }
+    #[inline(always)]
     fn get<K: Key, V: Value>(&self, _k: &K) -> KvResult<Option<V>> {
         self.0
             .as_ref()
diff --git a/rust-libs/tools/kv_typed/src/backend/sled.rs b/rust-libs/tools/kv_typed/src/backend/sled.rs
index ffef96fcfed42239a204de2d39478b75f3b6e069..6efd6cb2144035c5896afa99120005d8c45ea14c 100644
--- a/rust-libs/tools/kv_typed/src/backend/sled.rs
+++ b/rust-libs/tools/kv_typed/src/backend/sled.rs
@@ -76,6 +76,10 @@ impl BackendCol for SledCol {
         Ok(self.0.len())
     }
     #[inline(always)]
+    fn contains_key<K: Key>(&self, k: &K) -> KvResult<bool> {
+        k.as_bytes(|k_bytes| Ok(self.0.contains_key(k_bytes)?))
+    }
+    #[inline(always)]
     fn get<K: Key, V: Value>(&self, k: &K) -> KvResult<Option<V>> {
         k.as_bytes(|k_bytes| {
             self.0
diff --git a/rust-libs/tools/kv_typed/src/collection_ro.rs b/rust-libs/tools/kv_typed/src/collection_ro.rs
index 182031c7b5c6c4136da27de80b516b951d1a64d8..8096e05e5b6867e656d39cb861f27545bc40ba77 100644
--- a/rust-libs/tools/kv_typed/src/collection_ro.rs
+++ b/rust-libs/tools/kv_typed/src/collection_ro.rs
@@ -6,6 +6,7 @@ pub trait DbCollectionRo: Sized {
     type V: Value;
     type Event: EventTrait<K = Self::K, V = Self::V>;
 
+    fn contains_key(&self, k: &Self::K) -> KvResult<bool>;
     fn count(&self) -> KvResult<usize>;
     fn get(&self, k: &Self::K) -> KvResult<Option<Self::V>>;
     /// Don't worry about complex iter type. Use it like an `impl Iterator<Item=KvResult<(K, V)>>`.
@@ -67,6 +68,11 @@ impl<BC: BackendCol, E: EventTrait> DbCollectionRo for ColRo<BC, E> {
     type V = E::V;
     type Event = E;
 
+    #[inline(always)]
+    fn contains_key(&self, k: &Self::K) -> KvResult<bool> {
+        let r = self.inner.read();
+        r.backend_col.contains_key(k)
+    }
     #[inline(always)]
     fn count(&self) -> KvResult<usize> {
         let r = self.inner.read();