- Регистрация
- 1 Мар 2015
- Сообщения
- 11,730
- Баллы
- 155
The Best of Both Worlds: MongoDB's Familiar API with Deno's Native KV Store
Today, I'm excited to introduce Dengo, a MongoDB-compatible database layer
for Deno KV. Dengo brings the familiar MongoDB API to Deno's built-in key-value
store, allowing developers to leverage MongoDB's powerful query capabilities
while enjoying the simplicity and performance of Deno KV.
Why Dengo?
When building applications with Deno, especially for edge deployments, you often
need a database solution that is:
Deno's built-in KV store is perfect for edge deployments, but its API is quite
different from traditional document databases like MongoDB. This is where Dengo
comes in - it bridges this gap by providing a MongoDB-compatible API on top of
Deno KV.
Architecture Overview
Dengo is designed with simplicity and compatibility in mind. Here's how it
works:
Core Components
Dengo stores documents in Deno KV using a simple but effective approach:
// Documents are stored with collection name and document ID as the key
[collectionName, documentId] -> documentData
For indexes, we use a similar pattern:
// Indexes use a prefix to distinguish them from documents
[collectionName, "index", indexName, indexedValue] -> documentId
This storage model allows for efficient lookups by ID and indexed fields while
maintaining compatibility with MongoDB's document model.
MongoDB Compatibility
Dengo implements the core MongoDB API that most developers use daily:
Supported Query Operations
Here's a quick example of how Dengo's API mirrors MongoDB:
// MongoDB
const result = await db.collection("users")
.find({ age: { $gte: 21 } })
.sort({ lastName: 1 })
.limit(10);
// Dengo
const result = await db.collection("users")
.find({ age: { $gte: 21 } }, {
sort: { lastName: 1 },
limit: 10,
});
Implementation Details
Let's dive deeper into how Dengo implements some key MongoDB features:
Query Processing
When you execute a query like find({ name: "John", age: { $gt: 30 } }), Dengo:
Indexes are crucial for performance. Dengo supports:
Creating an index is as simple as:
await collection.createIndex({ key: { email: 1 }, options: { unique: true } });
Update Operations
Updates in Dengo follow MongoDB's semantics:
While Dengo provides MongoDB compatibility, it's important to understand the
performance implications:
For best performance:
One of Dengo's key advantages is its first-class TypeScript support:
interface User {
_id: ObjectId;
name: string;
email: string;
age: number;
tags: string[];
}
const users = db.collection<User>("users");
// TypeScript will ensure you're using the correct fields and types
const result = await users.findOne({
email: "john@example.com",
age: { $gte: 21 },
});
// result will be typed as User | null
Limitations and Future Work
While Dengo aims to provide a MongoDB-compatible experience, there are some
limitations:
Future versions of Dengo will address these limitations as Deno KV evolves.
Getting Started
Using Dengo is straightforward:
import { Database } from "dengo";
// Open a Deno KV database
const kv = await Deno.openKv();
// Create a Dengo database instance
const db = new Database(kv);
// Get a collection
const todos = db.collection("todos");
// Insert a document
await todos.insertOne({
title: "Learn Dengo",
completed: false,
createdAt: new Date(),
});
// Query documents
const incompleteTodos = await todos.find({ completed: false });
Conclusion
Dengo brings the best of both worlds to Deno developers - MongoDB's familiar and
powerful API with Deno's native KV store. It's perfect for:
We're excited to see what you build with Dengo! Check out our
for more examples and
documentation.
This post is part of the Dengo launch series. Stay tuned for more posts about
performance optimization, migration strategies, and real-world use cases.
Today, I'm excited to introduce Dengo, a MongoDB-compatible database layer
for Deno KV. Dengo brings the familiar MongoDB API to Deno's built-in key-value
store, allowing developers to leverage MongoDB's powerful query capabilities
while enjoying the simplicity and performance of Deno KV.
Why Dengo?
When building applications with Deno, especially for edge deployments, you often
need a database solution that is:
- Lightweight - No heavy dependencies or external services
- Familiar - Minimal learning curve for your team
- Type-safe - First-class TypeScript support
- Serverless-ready - Works seamlessly in edge functions
Deno's built-in KV store is perfect for edge deployments, but its API is quite
different from traditional document databases like MongoDB. This is where Dengo
comes in - it bridges this gap by providing a MongoDB-compatible API on top of
Deno KV.
Architecture Overview
Dengo is designed with simplicity and compatibility in mind. Here's how it
works:
Core Components
- Database Class: The entry point that manages collections
- Collection Class: Implements MongoDB-compatible operations
- Query Engine: Translates MongoDB queries to KV operations
- Index Management: Provides efficient querying capabilities
Dengo stores documents in Deno KV using a simple but effective approach:
// Documents are stored with collection name and document ID as the key
[collectionName, documentId] -> documentData
For indexes, we use a similar pattern:
// Indexes use a prefix to distinguish them from documents
[collectionName, "index", indexName, indexedValue] -> documentId
This storage model allows for efficient lookups by ID and indexed fields while
maintaining compatibility with MongoDB's document model.
MongoDB Compatibility
Dengo implements the core MongoDB API that most developers use daily:
Supported Query Operations
- find() and findOne() with filtering
- sort(), limit(), and skip() for result manipulation
- projection for selecting specific fields
- updateOne() and updateMany()
- $set, $unset, $inc, $push, and other update operators
- upsert capability for insert-or-update semantics
- Comparison: $eq, $gt, $gte, $lt, $lte, $ne, $in, $nin
- Logical: $and, $or, $nor, $not
- Array: $all, $elemMatch, $size
- Element: $exists, $type
Here's a quick example of how Dengo's API mirrors MongoDB:
// MongoDB
const result = await db.collection("users")
.find({ age: { $gte: 21 } })
.sort({ lastName: 1 })
.limit(10);
// Dengo
const result = await db.collection("users")
.find({ age: { $gte: 21 } }, {
sort: { lastName: 1 },
limit: 10,
});
Implementation Details
Let's dive deeper into how Dengo implements some key MongoDB features:
Query Processing
When you execute a query like find({ name: "John", age: { $gt: 30 } }), Dengo:
- Checks if there's an index that can be used for this query
- If an index exists, performs an efficient range scan
- If no index exists, falls back to a collection scan
- Filters documents based on the query conditions
- Applies sort, limit, and skip operations
Indexes are crucial for performance. Dengo supports:
- Single-field indexes: Optimize queries on a specific field
- Compound indexes: Optimize queries on multiple fields
- Unique indexes: Enforce uniqueness constraints
Creating an index is as simple as:
await collection.createIndex({ key: { email: 1 }, options: { unique: true } });
Update Operations
Updates in Dengo follow MongoDB's semantics:
- Find documents matching the filter
- Apply update operators to modify the documents
- Write the updated documents back to the store
- Return metadata about the operation (matchedCount, modifiedCount, etc.)
While Dengo provides MongoDB compatibility, it's important to understand the
performance implications:
- Indexed Queries: Extremely fast, similar to native KV lookups
- Non-Indexed Queries: Require full collection scans, which can be slow for large collections
- Complex Queries: May not perform as well as in MongoDB, especially for queries that would use specialized indexes in MongoDB
For best performance:
- Create indexes for frequently queried fields
- Limit the size of your collections
- Use more specific queries to leverage indexes effectively
One of Dengo's key advantages is its first-class TypeScript support:
interface User {
_id: ObjectId;
name: string;
email: string;
age: number;
tags: string[];
}
const users = db.collection<User>("users");
// TypeScript will ensure you're using the correct fields and types
const result = await users.findOne({
email: "john@example.com",
age: { $gte: 21 },
});
// result will be typed as User | null
Limitations and Future Work
While Dengo aims to provide a MongoDB-compatible experience, there are some
limitations:
- No Aggregation Framework: Complex data transformations need to be done in application code
- Limited Transaction Support: Only atomic operations on single documents are fully supported
- No Change Streams: Real-time updates are not currently supported
Future versions of Dengo will address these limitations as Deno KV evolves.
Getting Started
Using Dengo is straightforward:
import { Database } from "dengo";
// Open a Deno KV database
const kv = await Deno.openKv();
// Create a Dengo database instance
const db = new Database(kv);
// Get a collection
const todos = db.collection("todos");
// Insert a document
await todos.insertOne({
title: "Learn Dengo",
completed: false,
createdAt: new Date(),
});
// Query documents
const incompleteTodos = await todos.find({ completed: false });
Conclusion
Dengo brings the best of both worlds to Deno developers - MongoDB's familiar and
powerful API with Deno's native KV store. It's perfect for:
- Edge functions and serverless applications
- Projects migrating from MongoDB to Deno
- Developers who want a document database without external dependencies
We're excited to see what you build with Dengo! Check out our
for more examples and
documentation.
This post is part of the Dengo launch series. Stay tuned for more posts about
performance optimization, migration strategies, and real-world use cases.