> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kubiks.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# MongoDB

> OpenTelemetry instrumentation for MongoDB database operations

## Overview

`@kubiks/otel-mongodb` provides comprehensive OpenTelemetry instrumentation for the [MongoDB Node.js driver](https://www.mongodb.com/docs/drivers/node/). Capture spans for all database operations with detailed metadata about collections, queries, and execution metrics.

<Frame>
  <img src="https://mintcdn.com/kubiks-fb8cce26/MipPu38XDwLC2z34/images/otel/otel-mongodb-trace.png?fit=max&auto=format&n=MipPu38XDwLC2z34&q=85&s=6dd278c8e1ce26e6b7e082ec0350faa6" alt="MongoDB Trace Visualization" width="3379" height="2386" data-path="images/otel/otel-mongodb-trace.png" />
</Frame>

<Note>
  Visualize your MongoDB operations with detailed span information including collection names, operation types, and execution metrics.
</Note>

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @kubiks/otel-mongodb
  ```

  ```bash pnpm theme={null}
  pnpm add @kubiks/otel-mongodb
  ```

  ```bash yarn theme={null}
  yarn add @kubiks/otel-mongodb
  ```
</CodeGroup>

<Warning>
  **Peer Dependencies:** `@opentelemetry/api` >= 1.9.0, `mongodb` >= 5.0.0
</Warning>

## Quick Start

```typescript theme={null}
import { MongoClient } from "mongodb";
import { instrumentMongoClient } from "@kubiks/otel-mongodb";

const client = new MongoClient(process.env.MONGODB_URI!);
await client.connect();

instrumentMongoClient(client, {
  captureFilters: true,
  peerName: "mongodb.example.com",
  peerPort: 27017,
});

const db = client.db("myapp");
const users = db.collection("users");
const user = await users.findOne({ email: "user@example.com" });
```

<Tip>
  `instrumentMongoClient` wraps the client you already use—no configuration changes needed. Every database operation creates a client span with useful attributes.
</Tip>

## What Gets Traced

This instrumentation automatically traces all major MongoDB operations including:

<CardGroup cols={3}>
  <Card title="Find Operations" icon="magnifying-glass">
    `find`, `findOne`
  </Card>

  <Card title="Insert Operations" icon="plus">
    `insertOne`, `insertMany`
  </Card>

  <Card title="Update Operations" icon="pen">
    `updateOne`, `updateMany`, `findOneAndUpdate`
  </Card>

  <Card title="Delete Operations" icon="trash">
    `deleteOne`, `deleteMany`, `findOneAndDelete`
  </Card>

  <Card title="Aggregation" icon="chart-simple">
    `aggregate`
  </Card>

  <Card title="Count Operations" icon="hashtag">
    `countDocuments`
  </Card>
</CardGroup>

## Configuration

### With Filter Capture

```typescript theme={null}
instrumentMongoClient(client, {
  captureFilters: true,        // Capture query filters (default: false)
  peerName: "mongodb.example.com",
  peerPort: 27017,
});
```

<Warning>
  Filter capture is **disabled by default** to protect sensitive data. Only enable in secure, development environments or ensure filters don't contain sensitive information.
</Warning>

## Span Attributes

Each span includes rich metadata about the database operation following OpenTelemetry semantic conventions:

| Attribute                   | Description                           | Example                 |
| --------------------------- | ------------------------------------- | ----------------------- |
| `db.system`                 | Constant value `mongodb`              | `mongodb`               |
| `db.operation`              | MongoDB operation type                | `findOne`, `insertMany` |
| `db.mongodb.collection`     | Collection name                       | `users`                 |
| `db.name`                   | Database name                         | `myapp`                 |
| `net.peer.name`             | MongoDB server hostname               | `mongodb.example.com`   |
| `net.peer.port`             | MongoDB server port                   | `27017`                 |
| `mongodb.filter`            | Query filter (when enabled)           | `{"status":"active"}`   |
| `mongodb.result_count`      | Number of documents returned          | `42`                    |
| `mongodb.inserted_count`    | Number of documents inserted          | `5`                     |
| `mongodb.matched_count`     | Number of documents matched (updates) | `10`                    |
| `mongodb.modified_count`    | Number of documents modified          | `8`                     |
| `mongodb.deleted_count`     | Number of documents deleted           | `15`                    |
| `mongodb.execution_time_ms` | Query execution time (when enabled)   | `42.5`                  |
| `mongodb.pipeline`          | Aggregation pipeline                  | `[{"$match":...}]`      |

<Info>
  The instrumentation captures query metadata to help with debugging and monitoring, while optionally capturing filters based on your security requirements.
</Info>

## Usage Examples

### Basic Find Operations

<CodeGroup>
  ```typescript Find One theme={null}
  import { users } from "@/lib/mongodb";

  const user = await users.findOne({ email: "user@example.com" });

  // Traced with:
  // - db.operation: "findOne"
  // - db.mongodb.collection: "users"
  // - mongodb.result_count: 1
  ```

  ```typescript Find Many theme={null}
  const activeUsers = await users.find({ status: "active" }).toArray();

  // Traced with:
  // - db.operation: "find"
  // - db.mongodb.collection: "users"
  // - mongodb.result_count: 42
  // - mongodb.filter: {"status":"active"} (if captureFilters: true)
  ```

  ```typescript With Projection theme={null}
  const users = await collection.find(
    { status: "active" },
    { projection: { name: 1, email: 1 } }
  ).toArray();

  // Traced with projection metadata
  ```
</CodeGroup>

### Insert Operations

<CodeGroup>
  ```typescript Insert One theme={null}
  const result = await users.insertOne({
    name: "John Doe",
    email: "john@example.com",
    status: "active",
  });

  // Traced with:
  // - db.operation: "insertOne"
  // - mongodb.inserted_count: 1
  ```

  ```typescript Insert Many theme={null}
  const result = await users.insertMany([
    { name: "John", email: "john@example.com" },
    { name: "Jane", email: "jane@example.com" },
    { name: "Bob", email: "bob@example.com" },
  ]);

  // Traced with:
  // - db.operation: "insertMany"
  // - mongodb.inserted_count: 3
  ```
</CodeGroup>

### Update Operations

<CodeGroup>
  ```typescript Update One theme={null}
  const result = await users.updateOne(
    { email: "user@example.com" },
    { $set: { status: "inactive" } }
  );

  // Traced with:
  // - db.operation: "updateOne"
  // - mongodb.matched_count: 1
  // - mongodb.modified_count: 1
  ```

  ```typescript Update Many theme={null}
  const result = await users.updateMany(
    { status: "pending" },
    { $set: { status: "active" } }
  );

  // Traced with:
  // - db.operation: "updateMany"
  // - mongodb.matched_count: 10
  // - mongodb.modified_count: 10
  ```

  ```typescript Find and Update theme={null}
  const user = await users.findOneAndUpdate(
    { email: "user@example.com" },
    { $set: { lastLogin: new Date() } },
    { returnDocument: "after" }
  );

  // Traced with:
  // - db.operation: "findOneAndUpdate"
  // - mongodb.matched_count: 1
  // - mongodb.modified_count: 1
  ```
</CodeGroup>

### Delete Operations

<CodeGroup>
  ```typescript Delete One theme={null}
  const result = await users.deleteOne({ email: "user@example.com" });

  // Traced with:
  // - db.operation: "deleteOne"
  // - mongodb.deleted_count: 1
  ```

  ```typescript Delete Many theme={null}
  const result = await users.deleteMany({ status: "inactive" });

  // Traced with:
  // - db.operation: "deleteMany"
  // - mongodb.deleted_count: 15
  ```
</CodeGroup>

### Aggregation Pipeline

```typescript theme={null}
const pipeline = [
  { $match: { status: "active" } },
  { $group: { _id: "$country", count: { $sum: 1 } } },
  { $sort: { count: -1 } },
  { $limit: 10 },
];

const results = await users.aggregate(pipeline).toArray();

// Traced with:
// - db.operation: "aggregate"
// - mongodb.pipeline: [{"$match":...},{"$group":...}]
// - mongodb.result_count: 10
```

### Count Operations

<CodeGroup>
  ```typescript Count Documents theme={null}
  const count = await users.countDocuments({ status: "active" });

  // Traced with:
  // - db.operation: "countDocuments"
  // - mongodb.result_count: 42
  ```

  ```typescript Estimated Count theme={null}
  const count = await users.estimatedDocumentCount();

  // Traced with:
  // - db.operation: "estimatedDocumentCount"
  ```
</CodeGroup>

## Complete Integration Example

Here's a complete example of MongoDB with OpenTelemetry in a Next.js application:

### Setup

```typescript lib/mongodb.ts theme={null}
import { MongoClient } from "mongodb";
import { instrumentMongoClient } from "@kubiks/otel-mongodb";

if (!process.env.MONGODB_URI) {
  throw new Error("MONGODB_URI environment variable is not set");
}

const client = new MongoClient(process.env.MONGODB_URI);
let clientPromise: Promise<MongoClient>;

if (process.env.NODE_ENV === "development") {
  // In development, use a global variable to preserve the connection
  let globalWithMongo = global as typeof globalThis & {
    _mongoClientPromise?: Promise<MongoClient>;
  };

  if (!globalWithMongo._mongoClientPromise) {
    clientPromise = client.connect();
    instrumentMongoClient(client, {
      captureFilters: true,
      peerName: new URL(process.env.MONGODB_URI).hostname,
      peerPort: parseInt(new URL(process.env.MONGODB_URI).port || "27017"),
    });
    globalWithMongo._mongoClientPromise = clientPromise;
  } else {
    clientPromise = globalWithMongo._mongoClientPromise;
  }
} else {
  // In production, create a new connection
  clientPromise = client.connect();
  instrumentMongoClient(client, {
    captureFilters: false, // Disable in production
    peerName: new URL(process.env.MONGODB_URI).hostname,
    peerPort: parseInt(new URL(process.env.MONGODB_URI).port || "27017"),
  });
}

export default clientPromise;

export async function getDatabase() {
  const client = await clientPromise;
  return client.db("myapp");
}

export async function getCollection<T = any>(name: string) {
  const db = await getDatabase();
  return db.collection<T>(name);
}
```

### Usage in Server Actions

```typescript app/actions/users.ts theme={null}
"use server";

import { getCollection } from "@/lib/mongodb";
import { ObjectId } from "mongodb";

export async function getUser(userId: string) {
  const users = await getCollection("users");
  return await users.findOne({ _id: new ObjectId(userId) });
}

export async function createUser(data: { name: string; email: string }) {
  const users = await getCollection("users");
  const result = await users.insertOne({
    ...data,
    createdAt: new Date(),
    status: "active",
  });
  return { id: result.insertedId.toString() };
}

export async function updateUser(userId: string, data: Partial<{ name: string; email: string }>) {
  const users = await getCollection("users");
  const result = await users.updateOne(
    { _id: new ObjectId(userId) },
    { $set: { ...data, updatedAt: new Date() } }
  );
  return { success: result.modifiedCount > 0 };
}

export async function deleteUser(userId: string) {
  const users = await getCollection("users");
  const result = await users.deleteOne({ _id: new ObjectId(userId) });
  return { success: result.deletedCount > 0 };
}

export async function getActiveUsers() {
  const users = await getCollection("users");
  return await users.find({ status: "active" }).toArray();
}
```

### Usage in API Routes

```typescript app/api/stats/route.ts theme={null}
import { NextResponse } from "next/server";
import { getCollection } from "@/lib/mongodb";

export async function GET() {
  const users = await getCollection("users");
  
  const stats = await users.aggregate([
    {
      $group: {
        _id: "$status",
        count: { $sum: 1 },
      },
    },
    {
      $project: {
        status: "$_id",
        count: 1,
        _id: 0,
      },
    },
  ]).toArray();
  
  return NextResponse.json({ stats });
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use Connection Pooling">
    Always reuse the MongoDB client connection rather than creating new connections:

    ```typescript theme={null}
    // Good: Reuse client
    const client = await clientPromise;

    // Bad: Create new client each time
    const client = new MongoClient(uri);
    await client.connect();
    ```
  </Accordion>

  <Accordion title="Limit Filter Capture in Production">
    Only enable filter capture in development or when filters don't contain sensitive data:

    ```typescript theme={null}
    instrumentMongoClient(client, {
      captureFilters: process.env.NODE_ENV === "development",
    });
    ```
  </Accordion>

  <Accordion title="Use Indexes for Performance">
    Ensure proper indexes are created for frequently queried fields:

    ```typescript theme={null}
    await users.createIndex({ email: 1 }, { unique: true });
    await users.createIndex({ status: 1 });
    ```
  </Accordion>

  <Accordion title="Handle Errors Gracefully">
    Always handle MongoDB errors in your application:

    ```typescript theme={null}
    try {
      const user = await users.findOne({ email });
      if (!user) {
        throw new Error("User not found");
      }
      return user;
    } catch (error) {
      console.error("MongoDB error:", error);
      throw error;
    }
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Spans Not Appearing">
    Ensure OpenTelemetry is initialized before connecting to MongoDB:

    ```typescript theme={null}
    import { NodeSDK } from "@opentelemetry/sdk-node";

    const sdk = new NodeSDK({
      // ... configuration
    });

    sdk.start();

    // Then connect to MongoDB
    const client = await clientPromise;
    ```
  </Accordion>

  <Accordion title="Connection Errors">
    Make sure your MongoDB URI is correct and the server is accessible:

    ```bash theme={null}
    MONGODB_URI=mongodb://localhost:27017/myapp
    # or for MongoDB Atlas:
    MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/myapp
    ```
  </Accordion>

  <Accordion title="Missing Attributes">
    Ensure you've configured peer information:

    ```typescript theme={null}
    instrumentMongoClient(client, {
      peerName: "mongodb.example.com",
      peerPort: 27017,
    });
    ```
  </Accordion>
</AccordionGroup>

## Resources

<CardGroup cols={2}>
  <Card title="MongoDB Documentation" icon="book" href="https://www.mongodb.com/docs/drivers/node/">
    Learn more about MongoDB Node.js driver
  </Card>

  <Card title="GitHub Repository" icon="github" href="https://github.com/kubiks-inc/otel/tree/main/packages/otel-mongodb">
    View source code and examples
  </Card>

  <Card title="npm Package" icon="box" href="https://www.npmjs.com/package/@kubiks/otel-mongodb">
    View package on npm
  </Card>

  <Card title="Report Issues" icon="circle-exclamation" href="https://github.com/kubiks-inc/otel/issues">
    Found a bug? Let us know!
  </Card>
</CardGroup>

## License

MIT
