Tiny async/sync key–value store on top of MongoDB.
mongoKV is a tiny key–value store wrapper around MongoDB.
Think of it as: “I am a lazy programmer and I just want set and get over Mongo.” or Mongo as a dict instead of a database.
pip install mongokv
You’ll also need a running MongoDB instance and a valid connection URI, for example:
mongodb://localhost:27017
Each key is stored as a single MongoDB document:
{
"_id": "<str(key)>",
"value": <your_data>
}
str(key)), but you can pass any object that has a sensible str().asyncio event loop:
await them.Same methods, two modes.
from mongokv import Mkv
db = Mkv("mongodb://localhost:27017")
# Set a value with an explicit key
db.set("username", "harrison")
# Get it back
print(db.get("username")) # -> "harrison"
# Set a value with an auto-generated key
note_id = db.set(None, {"title": "mongoKV", "tags": ["mongo", "kv"]})
print(note_id) # -> e.g. "677eec65e92eeca23513fe99"
# List all keys
print(db.all()) # -> ["username", "677eec65e92eeca23513fe99", ...]
# Remove a key
db.remove("username")
# Clear everything
db.purge()
# Close connections when you’re done
db.close()
import asyncio
from mongokv import Mkv
db = Mkv("mongodb://localhost:27017")
async def main():
# Set a value with explicit key
await db.set("counter", 1)
# Increment and save again
current = await db.get("counter", 0)
await db.set("counter", current + 1)
# Auto-generated key
new_id = await db.set(None, {"hello": "world"})
print("New id:", new_id)
# List all keys
keys = await db.all()
print("Keys:", keys)
# Remove key
deleted = await db.remove("counter")
print("Deleted:", deleted)
# Purge all keys
await db.purge()
# Close connections
await db.close()
asyncio.run(main())
class MkvCreate a new mongoKV instance.
mongo_uri (str): MongoDB connection string.db_name (str, default "mkv"): Database name.collection_name (str, default "kv"): Collection name.Internally it maintains:
self._async_client = AsyncMongoClient(mongo_uri)self.db, self.collectionself._sync_client = MongoClient(mongo_uri)self._sync_db, self._sync_collectionThese are used automatically based on sync/async context.
setSet a value for a given key. If key is None, a new ObjectId-based key will be generated.
key (str or None):
None: converted to str(key) and used as _id.None: a new ObjectId() is generated and used as _id.value (Any): Any BSON-serializable object to store.str: The key used for this record.
db.set("user:1", {"name": "Alice"})
auto_id = db.set(None, {"name": "Bob"})
key = await db.set("session:123", {"state": "active"})
new_id = await db.set(None, {"foo": "bar"})
getFetch the value for a given key.
default is not provided, a missing key raises KeyError.default is provided (even None), that value is returned when missing.key (str): Key to look up (converted to str(key) for _id).default (Any, optional): Fallback to return if the key does not exist. If omitted, missing keys raise KeyError.The stored value. If the key is missing, returns default if provided, otherwise raises KeyError.
# strict (dict-like)
try:
user = db.get("user:1")
except KeyError:
user = None
# fallback behavior
user = db.get("user:1", default={})
missing = db.get("nope", default="N/A") # -> "N/A"
none_ok = db.get("nope", default=None) # -> None
# strict (dict-like)
try:
user = await db.get("user:1")
except KeyError:
user = None
# fallback behavior
user = await db.get("user:1", default={})
none_ok = await db.get("nope", default=None)
removeDelete a single document by key.
True if a document was deleted, False otherwise.True or False.key (str): Key to remove (converted to str(key) for _id).bool: True if a document was deleted, False otherwise.
deleted = db.remove("user:1")
if deleted:
print("User removed")
deleted = await db.remove("user:1")
allList all keys (all _id values) in the collection.
list[str].list[str].list[str]: All keys currently stored.
keys = db.all()
print(keys) # -> ["user:1", "note:abc", ...]
keys = await db.all()
purgeDelete all documents in the collection. Use with care.
True once the operation completes.True.bool: Always True if no exception is raised.
db.purge() # All keys gone
await db.purge()
closeClose both the async and sync MongoDB clients.
asyncio.run(self._async_client.close()).self._sync_client.close().None.await self._async_client.close()self._sync_client.close()None.db.close()
await db.close()
Closing is optional in short-lived scripts, but recommended in long-running apps and tests.
The library uses:
def in_async() -> bool:
try:
asyncio.get_running_loop()
return True
except RuntimeError:
return False
set, get, etc. return coroutines.Examples:
# Sync context
db = Mkv("mongodb://localhost:27017")
db.set("x", 1) # OK
value = db.get("x") # OK
# Async context
async def foo():
db = Mkv("mongodb://localhost:27017")
await db.set("x", 1) # must await
value = await db.get("x")
# Don’t do this in async code:
db.set("x", 1) # returns a coroutine, but you never await it
The current implementation doesn’t wrap MongoDB errors – any connection or operation issue will bubble up as a PyMongo/AsyncMongo exception. Typical things you might see:
You can catch them at the call site:
from pymongo.errors import PyMongoError
try:
db.set("x", object())
except PyMongoError as e:
print("Mongo blew up:", e)