Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ playground's README states what it needs.

## Playgrounds

| Playground | Language / Stack | What it shows |
| --------------------------------- | ---------------------- | ------------------------------------------------------------------------- |
| [mongoose](playgrounds/mongoose/) | Node.js — Mongoose ODM | Express REST API + a CRUD/compatibility test suite using the Mongoose ODM. |
| [beanie](playgrounds/beanie/) | Python — Beanie ODM | FastAPI REST API + a CRUD/compatibility test suite using the Beanie ODM. |
| [pymongo](playgrounds/pymongo/) | Python — PyMongo driver | Flask REST API + a CRUD/compatibility test suite using the raw PyMongo driver. |
| Playground | Language / Stack | What it shows |
| --------------------------------------- | ------------------------ | -------------------------------------------------------------------------------- |
| [mongoose](playgrounds/mongoose/) | Node.js — Mongoose ODM | Express REST API + a CRUD/compatibility test suite using the Mongoose ODM. |
| [mongodb-node](playgrounds/mongodb-node/) | Node.js — MongoDB driver | Express REST API + a CRUD/compatibility suite using the native Node.js driver. |
| [beanie](playgrounds/beanie/) | Python — Beanie ODM | FastAPI REST API + a CRUD/compatibility test suite using the Beanie ODM. |
| [pymongo](playgrounds/pymongo/) | Python — PyMongo driver | Flask REST API + a CRUD/compatibility test suite using the raw PyMongo driver. |

More playgrounds are planned (for example the **MongoDB Node.js native driver**
and other MongoDB drivers). Contributions are welcome.
More MongoDB driver playgrounds are planned. Contributions are welcome.

## Getting Started

Expand All @@ -38,6 +38,14 @@ cd playgrounds/mongoose
./scripts/run-app.sh # or run the demo REST API
```

To try the MongoDB Node.js native driver playground:

```bash
cd playgrounds/mongodb-node
./scripts/run-test.sh # start DocumentDB locally and run the compatibility suite
./scripts/run-app.sh # or run the demo REST API
```

To try the Beanie playground:

```bash
Expand All @@ -62,6 +70,7 @@ documentdb-playground/
├── LICENSE
└── playgrounds/
├── mongoose/ # Node.js + Mongoose ODM
├── mongodb-node/ # Node.js + MongoDB native driver
├── beanie/ # Python + Beanie ODM
└── pymongo/ # Python + PyMongo driver
```
Expand Down
173 changes: 173 additions & 0 deletions playgrounds/mongodb-node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# MongoDB Node.js Driver with DocumentDB (local)

This playground uses the official [MongoDB Node.js driver](https://www.mongodb.com/docs/drivers/node/current/)
against a local [DocumentDB](https://github.com/documentdb/documentdb) instance.
It includes:

- an **Express REST API** using native collections (`app/server.js`), and
- a standalone **CRUD/compatibility suite** (`app/mongodb-crud-test.js`) that
exercises connection, indexes, inserts, queries, updates, aggregation,
unique-index enforcement, vector search, deletion, and cleanup.

The Node.js driver is the low-level MongoDB client used directly here, without
an ODM such as Mongoose. DocumentDB runs in Docker while the app and tests run
as local Node.js processes.

## Prerequisites

- **Docker** (Docker Desktop or a Docker daemon)
- **Node.js 18+** and **npm**

## Quick Start

From `playgrounds/mongodb-node/`, choose either independent operation:

```bash
# Start DocumentDB and run the compatibility suite.
./scripts/run-test.sh

# Or start DocumentDB and serve the API on port 3000.
./scripts/run-app.sh
```

Both commands reuse the same `documentdb-local` container if it is running.
The API uses the `mongodb_node_demo` database and the suite uses
`mongodb_node_test`, so they can run at the same time.

Stop and remove DocumentDB when finished:

```bash
./scripts/stop-documentdb.sh
```

Set `KEEP_DB=0` when running the suite to remove the container automatically:

```bash
KEEP_DB=0 ./scripts/run-test.sh
```

## Trying the API

With `./scripts/run-app.sh` running:

```bash
curl -s http://localhost:3000/health

curl -s -X POST http://localhost:3000/books \
-H 'Content-Type: application/json' \
-d '{"title":"Dune","author":"Herbert","genres":["sci-fi"],"pages":412,"rating":5}'

curl -s http://localhost:3000/books | jq .
curl -s 'http://localhost:3000/books?author=Herbert' | jq .
curl -s http://localhost:3000/stats/genres | jq .
```

The API also provides `GET`, `PATCH`, and `DELETE /books/:id`.

## Connecting the Native Driver

DocumentDB's local gateway uses TLS, a self-signed certificate, and standalone
topology. The client therefore uses these options from `app/db.js`:

```js
const client = new MongoClient(uri, {
directConnection: true,
tls: true,
tlsAllowInvalidCertificates: true,
serverSelectionTimeoutMS: 10000,
});
```

The playground removes `replicaSet` from supplied URIs because it conflicts
with `directConnection` against the standalone gateway. For production, set
`TLS_INSECURE=false` and configure a trusted CA rather than accepting an
unverified certificate.

## Scripts

| Script | Purpose |
| --- | --- |
| `scripts/run-test.sh` | Start DocumentDB, install dependencies, and run the compatibility suite. |
| `scripts/run-app.sh` | Start DocumentDB, install dependencies, and run the Express API. |
| `scripts/start-documentdb.sh` | Start the local container and wait for readiness. |
| `scripts/stop-documentdb.sh` | Stop and remove the local container. |
| `scripts/lib.sh` | Shared lifecycle and connection-string helpers. |

## Configuration

| Variable | Default | Description |
| --- | --- | --- |
| `DOCUMENTDB_IMAGE` | `ghcr.io/documentdb/documentdb/documentdb-local:latest` | Local DocumentDB image. |
| `DOCUMENTDB_CONTAINER` | `documentdb-local` | Container name. |
| `DOCUMENTDB_PORT` | `10260` | Loopback host port. |
| `DOCUMENTDB_USERNAME` | `docdbadmin` | Gateway username. |
| `DOCUMENTDB_PASSWORD` | `Documentdb!Local1` | Development password. |
| `MONGO_URI` | Local URI using the defaults above | Driver connection string. |
| `MONGO_DB` | `mongodb_node_demo` or `mongodb_node_test` | App or test database. |
| `TLS_INSECURE` | `true` | Accept the local self-signed certificate. |
| `SERVER_SELECTION_TIMEOUT_MS` | `10000` | App server-selection timeout. |
| `PORT` | `3000` | REST API port. |
| `RATE_LIMIT_WINDOW_MS` | `60000` | Time window for rate limiting data routes. |
| `RATE_LIMIT_MAX` | `100` | Maximum requests per client within the rate-limit window. |
| `KEEP_DB` | `1` | Set to `0` to remove DocumentDB after tests. |

## Running the Suite Manually

```bash
cd app
npm install
MONGO_URI='mongodb://docdbadmin:Documentdb!Local1@localhost:10260/?tls=true&tlsAllowInvalidCertificates=true&directConnection=true' \
npm run test:crud
```

Expected summary:

```text
MongoDB Node.js driver DocumentDB compatibility test
====================================================
✅ connect
✅ create indexes
✅ insertOne
...
✅ $vectorSearch returns nearest neighbor
✅ cleanup (drop collection)
====================================================
Passed: 16 Failed: 0
```

## Compatibility Notes

| Native driver feature | Status | Notes |
| --- | --- | --- |
| CRUD and `_id` lookups | Supported | Uses `insertOne`, `findOne`, `updateOne`, and `deleteOne`. |
| Compound and unique indexes | Supported | Index collation is not supported by DocumentDB. |
| Aggregation | Common stages supported | The suite covers `$unwind`, `$group`, and `$sort`. |
| Vector search | Supported | Uses a `cosmosSearch` vector index and `$vectorSearch`. |
| Transactions/change streams | Not covered | The local gateway advertises standalone topology. |

## Directory Layout

```text
mongodb-node/
├── README.md
├── app/
│ ├── package.json
│ ├── db.js
│ ├── server.js
│ └── mongodb-crud-test.js
└── scripts/
├── lib.sh
├── start-documentdb.sh
├── stop-documentdb.sh
├── run-app.sh
└── run-test.sh
```

## Troubleshooting

- If Docker is unreachable, start Docker Desktop or the Docker daemon.
- For selection timeouts, check `docker logs documentdb-local` and verify port
`10260` is reachable on `localhost`.
- If credentials change, remove the old container before restarting it because
credentials are set when the container is created.
- Omit index `collation`; DocumentDB does not implement it.
43 changes: 43 additions & 0 deletions playgrounds/mongodb-node/app/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict';

const { MongoClient } = require('mongodb');

const DEFAULT_URI =
'mongodb://docdbadmin:Documentdb!Local1@localhost:10260/?tls=true&tlsAllowInvalidCertificates=true&directConnection=true';

let client;
let database;

function sanitizeUri(uri = DEFAULT_URI) {
return uri.replace(/([?&])replicaSet=[^&]*(&|$)/g, (_match, lead, trail) =>
lead === '?' && trail === '&' ? '?' : trail === '&' ? lead : ''
);
}

function buildOptions() {
return {
directConnection: true,
tls: true,
tlsAllowInvalidCertificates:
(process.env.TLS_INSECURE || 'true').toLowerCase() !== 'false',
serverSelectionTimeoutMS: Number(process.env.SERVER_SELECTION_TIMEOUT_MS || 10000),
};
}

async function connect() {
if (database) return database;

client = new MongoClient(sanitizeUri(process.env.MONGO_URI), buildOptions());
await client.connect();
database = client.db(process.env.MONGO_DB || 'mongodb_node_demo');
await database.command({ ping: 1 });
return database;
}

async function close() {
if (client) await client.close();
client = undefined;
database = undefined;
}

module.exports = { connect, close, sanitizeUri, buildOptions, DEFAULT_URI };
Loading
Loading