A lightweight NoSQL-like database in Python
Project description
nosqlpy - Async, NoSQL, MQL-style embedded document store for Python
⚠️ Warning: This is the alpha version
nosqlpy is a lightweight, async-first, file-backed document database for Python that speaks a MongoDB-like Query Language (MQL). It’s designed for small-to-medium apps, dev tooling, prototyping, CLI tools, and apps that want a simple embedded DB with async/await, durability options, indexes, and a clean API - without running a separate database server.
- ✅ Async-first
- ✅ Mongo-like queries
- ✅ Append-only op-log
- ✅ Secondary equality indexes
- ✅ Compaction & durability modes
Table of contents
- nosqlpy - Async, NoSQL, MQL-style embedded document store for Python
- Table of contents
- Why nosqlpy?
- Key features
- Installation
- Quickstart
- Core concepts & API reference
- Performance tips
- License
- Keywords
Why nosqlpy?
Many small Python apps need an embedded document store that:
- Is async-native (fits FastAPI / aiohttp / asyncio apps)
- Uses a familiar query language (MongoDB-style filters)
- Provides durable writes and safe recovery
- Enables fast reads using secondary indexes
Most small DB options are either synchronous (TinyDB), or require wrapping sync code into thread pools. nosqlpy is built async-first and offers MQL-style queries, an append-only op-log for safe durability, optional indexes, and compaction for production-ish workloads - all in a single small dependency set.
Key features
- Async API (
async/await) - designed for asyncio apps - MongoDB-style query language (subset):
$and,$or,$not,$gt,$gte,$lt,$lte,$in,$nin,$exists, simple dot-notation for nested fields - Update operators:
$set,$unset,$inc,$push,$pull - Append-only operation log (oplog) with replayable history
- Durability modes:
fast,safe,durable(fsync) - Secondary equality indexes (create and use for fast
field == value) - Compaction (background-friendly pattern) to shrink logs and produce snapshots
- Bulk ops:
insert_many,update_many,delete_many - find support:
projection,sort,skip,limit,find_one - TinyDB migration helper / compatibility shim (to ease switching)
Installation
# install from PyPI (when published)
pip install nosqlpy
# or during development (from repo)
git clone https://github.com/viehoang/nosqlpy.git
cd nosqlpy
pip install -e ".[dev]"
Dependencies: aiofiles (async file I/O). Dev/test extras include pytest, pytest-asyncio.
Quickstart
import asyncio
from nosqlpy import Database
async def main():
db = Database("data_dir", durability="safe")
users = await db.collection("users")
# insert
uid = await users.insert_one({
"name": "alice",
"age": 30})
print("inserted id:", uid)
# find (Mongo-like query)
results = await users.find(
{"age": {"$gte": 25},
"name": "alice"})
print("found:", results)
# update operators
await users.update_many(
{"name": "alice"},
{"$inc": {"age": 1},
"$push": {"tags": "admin"}})
# create index on email for fast equality lookups
await users.create_index("email")
# compact (shrink the op-log)
await users.compact()
asyncio.run(main())
Core concepts & API reference
Collection - a single named dataset backed by an append-oplog file.
Document - a JSON-like dict with an
_idfield (string) as the primary key.Op-log - append-only lines describing
insert,update,replace,deleteoperations.
All calls are async.
Database & Collection
from nosqlpy import Database
db = Database("my_data_dir", durability="safe")
users = await db.collection("users")
Common operations
List of operations
| Operator | Description |
|---|---|
open |
Asynchronously open and load the collection. |
insert_one |
Insert a single document into the collection. |
insert_many |
Insert multiple documents into the collection. |
find |
Find documents matching the query, with options for projection, sort, skip, and limit. |
find_one |
Find a single document matching the query. |
count |
Count the number of documents matching the query. |
delete_one |
Delete a single document matching the query. |
delete_many |
Delete multiple documents matching the query. |
update_one |
Update a single document matching the query, with optional upsert. |
update_many |
Update multiple documents matching the query, with optional upsert (upserts one if no matches). |
replace_one |
Replace a single document matching the query, with optional upsert. |
create_index |
Create a secondary hash index on a field. |
drop_index |
Drop the index on a field. |
compact |
Compact the op-log by replacing it with current state as inserts. |
Examples
# insert one
_id = await users.insert_one({"name": "Bob", "age": 22})
# insert many
ids = await users.insert_many([{"name":"A"},{"name":"B"}])
# find (MQL filter)
docs = await users.find(
{"age": {"$gte": 18}},
projection=["name","age"],
sort=[("age", -1)],
skip=0,
limit=50)
# find one
doc = await users.find_one({"name": "Bob"})
# count
n = await users.count({"age": {"$gte": 30}})
# update many (supports $set/$inc/$push/$pull)
updated = await users.update_many(
{"name": "Bob"},
{"$inc": {"age": 1}})
# replace one
ok = await users.replace_one(
{"name": "Bob"},
{"name": "Robert", "age": 23})
# delete many
deleted = await users.delete_many({"age": {"$lt": 18}})
# compact (rewrite op-log as current-state snapshot)
await users.compact()
Query language (MQL subset)
Supported query operators (subset):
- Comparison:
$eq(or plain value),$ne,$gt,$gte,$lt,$lte - Membership:
$in,$nin - Existence:
$exists - Logical:
$and,$or,$not - Dot-notation:
"user.age"for nested fields
Examples:
# age >= 30 AND (country == "US" OR country == "JP")
q = {"$and": [{"age": {"$gte": 30}}, {"$or": [{"country": "US"}, {"country": "JP"}]}]}
# membership
q2 = {"status": {"$in": ["active", "pending"]}}
# nested field
q3 = {"profile.email": {"$exists": True}}
Update operators
Supported update operators:
$set: set field(s) to value$unset: remove field(s)$inc: increment numeric field$push: append to array field$pull: remove value(s) from array field
Example:
await users.update_many(
{"_id": some_id},
{
"$set": {"name": "Alice"},
"$inc": {"score": 10}
})
Indexing
Equality secondary index (hash-based) to accelerate queries like { "email": "a@x.com" }:
await users.create_index("email")
Notes:
- Indexes are in-memory by default and rebuilt on create; consider snapshotting indexes for very large DBs (TODO/roadmap).
- Planner currently optimizes single-field equality queries; range indexes are a planned feature.
Compaction & durability
-
Op-log (append-only) is crash friendly: each write is a single line append.
-
Durability modes:
fast: minimal overhead, no explicit flush (best throughput, less durable)safe: flush after write (file.flush()) - good compromisedurable:fsync()after each op (strong durability, slower)
Compaction rewrites the current state as a compact snapshot (series of insert ops) and atomically replaces the op-log. For large DBs we recommend:
- Run
compact()occasionally (or use background segmented compaction; see Roadmap). - Use
durablefor critical writes,safefor normal persistence.
Performance tips
- Use indexes for frequent equality lookups.
- Use
durability="safe"for most apps; switch todurableonly if you need fsync-level guarantees on every op. - For very large data (>100k docs), enable segmented compaction or index snapshots (planned).
License
nosqlpy is released under the MIT License. See LICENSE for details.
Keywords
nosqlpy, nosqlite, nosql lite, async nosql, python async database, embedded document store, mongo query language python, mql python, asyncio database, append log database, python nosql lite, tinydb alternative, aiosqlite alternative, lightweight mongodb, file-backed document store
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nosqlpy-0.1.1.tar.gz.
File metadata
- Download URL: nosqlpy-0.1.1.tar.gz
- Upload date:
- Size: 5.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df7a5736e8b9f4062d9553600f011bf89eace34c3d7ab69b1b8d9985de45ca58
|
|
| MD5 |
6b3117232d4fc482f8b05bf55a80a426
|
|
| BLAKE2b-256 |
edb5f3cd5b272c680bb51133263d08ce2c69ce1f80f8ae905abde786445f31bd
|
File details
Details for the file nosqlpy-0.1.1-py3-none-any.whl.
File metadata
- Download URL: nosqlpy-0.1.1-py3-none-any.whl
- Upload date:
- Size: 4.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67af607379277bb85c7ef75c53400a7cbabff2466095fa44dfe1d378a1345fcb
|
|
| MD5 |
e03322db6e05ac8ff140bed808db3460
|
|
| BLAKE2b-256 |
598810345ad138246ee23e5aa3c819f812dd05142ea3617bc59448a7dceb46bf
|