# Mongo-Bolt

Mongo-Bolt is a lightweight, modern MongoDB wrapper built on top of Mongoose, designed to simplify database operations with an intuitive, beginner-friendly API. It provides robust tools for connecting to MongoDB, managing collections, performing CRUD operations, handling transactions, building aggregation pipelines, and managing indexes. With inbuilt caching, simplified joins, and streamlined indexing, Mongo-Bolt is ideal for Node.js developers building efficient and scalable applications.

Inspired by the clarity and interactivity of Docs by Hashnode, this documentation offers a modular, developer-centric guide to Mongo-Bolt. The `AggregationBuilder` class simplifies MongoDB’s complex aggregation pipelines, making them accessible to beginners and powerful for advanced users. Whether you're new to MongoDB or an experienced developer, Mongo-Bolt empowers you to work with MongoDB efficiently.

## Why Mongo-Bolt?

Mongo-Bolt stands out with features tailored to enhance developer experience and performance:

- **Beginner-Friendly**: Intuitive method names, clear error messages, and a streamlined API reduce the learning curve for MongoDB.
- **Inbuilt Caching**: Improves performance for repeated queries by caching results (implementation details to be covered in a forthcoming blog).
- **Simplified Joins, Indexing, and Multi-Collection Fetching**: Methods like `findAndPopulateById`, `findAndPopulateByKey`, and index management make complex operations straightforward.

## Table of Contents

- [Installation](#installation)
- [Getting Started](#getting-started)
- [Configuration](#configuration)
- [Methods](#methods)
  - [MongoDB Class Methods](#mongodb-class-methods)
    - [connect](#connect)
    - [createStore](#createstore)
    - [insertItem](#insertitem)
    - [insertItems](#insertitems)
    - [findItem](#finditem)
    - [updateItems](#updateitems)
    - [deleteStore](#deletestore)
    - [dropItem](#dropitem)
    - [dropItems](#dropitems)
    - [truncateStore](#truncatestore)
    - [alterStore](#alterstore)
    - [findAndPopulateById](#findandpopulatebyid)
    - [aggregate](#aggregate)
    - [pipelineBuilder](#pipelinebuilder)
    - [createIndex](#createindex)
    - [viewIndexes](#viewindexes)
    - [dropIndex](#dropindex)
    - [findAndPopulateByKey](#findandpopulatebykey)
    - [startTransaction](#starttransaction)
    - [commitTransaction](#committransaction)
    - [abortTransaction](#aborttransaction)
    - [getSession](#getsession)
    - [getMongoose](#getmongoose)
    - [disconnect](#disconnect)
  - [AggregationBuilder Methods](#aggregationbuilder-methods)
    - [match](#match)
    - [group](#group)
    - [sum](#sum)
    - [avg](#avg)
    - [min](#min)
    - [max](#max)
    - [first](#first)
    - [last](#last)
    - [push](#push)
    - [addToSet](#addtoset)
    - [stdDevPop](#stddevpop)
    - [stdDevSamp](#stddevsamp)
    - [mergeObjects](#mergeobjects)
    - [count](#count)
    - [project](#project)
    - [sort](#sort)
    - [limit](#limit)
    - [skip](#skip)
    - [lookup](#lookup)
    - [unset](#unset)
    - [addFields](#addfields)
    - [replaceRoot](#replaceroot)
    - [replaceWith](#replacewith)
    - [graphLookup](#graphlookup)
    - [unwind](#unwind)
    - [bucket](#bucket)
    - [bucketAuto](#bucketauto)
    - [facet](#facet)
    - [merge](#merge)
    - [out](#out)
    - [search](#search)
    - [searchMeta](#searchmeta)
    - [redact](#redact)
    - [indexStats](#indexstats)
    - [currentOp](#currentop)
    - [collStats](#collstats)
    - [planCacheStats](#plancachestats)
    - [listSessions](#listsessions)
    - [build](#build)
- [Advanced Usage](#advanced-usage)
  - [Transaction Management](#transaction-management)
  - [Aggregation Pipelines](#aggregation-pipelines)
  - [Index Management](#index-management)
- [Examples](#examples)
  - [Complete CRUD Workflow](#complete-crud-workflow)
  - [Populating Related Data](#populating-related-data)
  - [Building an Aggregation Pipeline](#building-an-aggregation-pipeline)
- [Error Handling](#error-handling)
- [Contributing](#contributing)
- [License](#license)

## Installation

Install Mongo-Bolt via npm:

```bash
npm install mongo-bolt
```

Mongo-Bolt requires Mongoose as a peer dependency. Install it if not already present:

```bash
npm install mongoose
```

## Getting Started

To start using Mongo-Bolt, import the `MongoDB` class, configure your MongoDB connection, and connect to your database:

```javascript
import MongoDB from 'mongo-bolt';

const config = {
  uri: 'mongodb://localhost:27017/mydb',
  options: {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  },
};

const db = new MongoDB(config);

async function init() {
  try {
    await db.connect();
    console.log('Connected to MongoDB');
  } catch (error) {
    console.error('Connection failed:', error.message);
  }
}

init();
```

This example showcases Mongo-Bolt’s beginner-friendly setup, inspired by Hashnode Docs’ intuitive onboarding.

## Configuration

The `MongoDB` constructor accepts a `config` object with the following properties:

| Property  | Type     | Description                                                                 | Required |
|-----------|----------|-----------------------------------------------------------------------------|----------|
| `uri`     | `string` | MongoDB connection URI (e.g., `mongodb://localhost:27017/mydb`)            | Yes      |
| `options` | `object` | Mongoose connection options (e.g., `{ useNewUrlParser: true }`)            | No       |

**Example:**

```javascript
const config = {
  uri: 'mongodb://localhost:27017/mydb',
  options: {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    serverSelectionTimeoutMS: 5000,
  },
};
```

## Methods

Mongo-Bolt provides two primary interfaces: the `MongoDB` class for core database operations and the `AggregationBuilder` class for constructing aggregation pipelines. Each method is documented with its signature, parameters, return value, and an example, ensuring clarity and interactivity akin to Hashnode Docs.

### MongoDB Class Methods

#### connect

Establishes a connection to the MongoDB database.

**Signature:**

```javascript
async connect(): Promise<void>
```

**Returns:**
- `Promise<void>`: Resolves when the connection is successful, or rejects with an error.

**Example:**

```javascript
const db = new MongoDB(config);
await db.connect();
console.log('Database connected');
```

#### createStore

Creates a new collection with a specified schema.

**Signature:**

```javascript
async createStore<T>(
  collectionName: string,
  schema: SchemaDefinition<SchemaDefinitionType<T>>
): Promise<void>
```

**Parameters:**

| Parameter        | Type                              | Description                                                       | Required |
|------------------|-----------------------------------|-------------------------------------------------------------------|----------|
| `collectionName` | `string`                          | Name of the collection to create.                                 | Yes      |
| `schema`         | `SchemaDefinition<SchemaDefinitionType<T>>` | Mongoose schema definition for the collection.           | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the collection is created, or rejects with an error.

**Example:**

```javascript
import { Schema } from 'mongoose';

const userSchema = {
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
};

const db = new MongoDB(config);
await db.connect();
await db.createStore('users', userSchema);
console.log('Users collection created');
```

#### insertItem

Inserts a single document into a collection.

**Signature:**

```javascript
async insertItem<T>(collectionName: string, documentData: T): Promise<void>
```

**Parameters:**

| Parameter        | Type     | Description                                              | Required |
|------------------|----------|----------------------------------------------------------|----------|
| `collectionName` | `string` | Name of the collection to insert into.                   | Yes      |
| `documentData`   | `T`      | The document data to insert.                             | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the document is inserted, or rejects with an error.

**Example:**

```javascript
const user = {
  name: 'John Doe',
  email: 'john@example.com',
};

await db.insertItem('users', user);
console.log('User inserted');
```

#### insertItems

Inserts multiple documents into a collection.

**Signature:**

```javascript
async insertItems<T>(collectionName: string, documentsData: T[]): Promise<void>
```

**Parameters:**

| Parameter        | Type     | Description                                              | Required |
|------------------|----------|----------------------------------------------------------|----------|
| `collectionName` | `string` | Name of the collection to insert into.                   | Yes      |
| `documentsData`  | `T[]`    | Array of document data to insert.                        | Yes      |

**Returns:**
- `Promise<void>`: Resolves when all documents are inserted, or rejects with an error.

**Example:**

```javascript
const users = [
  { name: 'Jane Doe', email: 'jane@example.com' },
  { name: 'Bob Smith', email: 'bob@example.com' },
];

await db.insertItems('users', users);
console.log('Users inserted');
```

#### findItem

Retrieves documents from a collection based on a query.

**Signature:**

```javascript
async findItem<T>(
  collectionName: string,
  query: Record<string, any> = {}
): Promise<T[]>
```

**Parameters:**

| Parameter        | Type                    | Description                                              | Required |
|------------------|-------------------------|----------------------------------------------------------|----------|
| `collectionName` | `string`                | Name of the collection to query.                         | Yes      |
| `query`          | `Record<string, any>`   | Query object to filter documents (default: `{}`).        | No       |

**Returns:**
- `Promise<T[]>`: An array of documents matching the query.

**Example:**

```javascript
const users = await db.findItem('users', { name: 'John Doe' });
console.log(users); // [{ name: 'John Doe', email: 'john@example.com', ... }]
```

#### updateItems

Updates multiple documents in a collection based on a query.

**Signature:**

```javascript
async updateItems(
  collectionName: string,
  query: Record<string, any>,
  update: Record<string, any>
): Promise<number>
```

**Parameters:**

| Parameter        | Type                    | Description                                              | Required |
|------------------|-------------------------|----------------------------------------------------------|----------|
| `collectionName` | `string`                | Name of the collection to update.                        | Yes      |
| `query`          | `Record<string, any>`   | Query to select documents to update.                     | Yes      |
| `update`         | `Record<string, any>`   | Update operations to apply (e.g., `{ $set: { ... } }`).  | Yes      |

**Returns:**
- `Promise<number>`: The number of documents updated.

**Example:**

```javascript
const updatedCount = await db.updateItems(
  'users',
  { name: 'John Doe' },
  { $set: { email: 'john.doe@example.com' } }
);
console.log(`${updatedCount} users updated`);
```

#### deleteStore

Deletes a collection from the database.

**Signature:**

```javascript
async deleteStore(collectionName: string): Promise<void>
```

**Parameters:**

| Parameter        | Type     | Description                                              | Required |
|------------------|----------|----------------------------------------------------------|----------|
| `collectionName` | `string` | Name of the collection to delete.                        | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the collection is deleted, or rejects with an error.

**Example:**

```javascript
await db.deleteStore('users');
console.log('Users collection deleted');
```

#### dropItem

Deletes a single document from a collection based on a query.

**Signature:**

```javascript
async dropItem(
  storeName: string,
  itemInfo: Record<string, any>
): Promise<void>
```

**Parameters:**

| Parameter    | Type                    | Description                                              | Required |
|--------------|-------------------------|----------------------------------------------------------|----------|
| `storeName`  | `string`                | Name of the collection to delete from.                   | Yes      |
| `itemInfo`   | `Record<string, any>`   | Query to identify the document to delete.                | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the document is deleted, or rejects with an error.

**Example:**

```javascript
await db.dropItem('users', { email: 'john@example.com' });
console.log('User dropped');
```

#### dropItems

Deletes multiple documents from a collection based on a query.

**Signature:**

```javascript
async dropItems(
  storeName: string,
  itemInfo: Record<string, any>
): Promise<void>
```

**Parameters:**

| Parameter    | Type                    | Description                                              | Required |
|--------------|-------------------------|----------------------------------------------------------|----------|
| `storeName`  | `string`                | Name of the collection to delete from.                   | Yes      |
| `itemInfo`   | `Record<string, any>`   | Query to identify documents to delete.                   | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the documents are deleted, or rejects with an error.

**Example:**

```javascript
await db.dropItems('users', { name: 'John Doe' });
console.log('Users dropped');
```

#### truncateStore

Removes all documents from a collection without deleting the collection itself.

**Signature:**

```javascript
async truncateStore(storeName: string): Promise<void>
```

**Parameters:**

| Parameter    | Type     | Description                                              | Required |
|--------------|----------|----------------------------------------------------------|----------|
| `storeName`  | `string` | Name of the collection to truncate.                      | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the collection is truncated, or rejects with an error.

**Example:**

```javascript
await db.truncateStore('users');
console.log('Users collection truncated');
```

#### alterStore

Modifies the schema of an existing collection and updates documents as needed.

**Signature:**

```javascript
async alterStore<T, U>(
  storeName: string,
  newSchema: SchemaDefinition<SchemaDefinitionType<U>>,
  changeValues: Record<string, any>
): Promise<void>
```

**Parameters:**

| Parameter      | Type                              | Description                                                       | Required |
|----------------|-----------------------------------|-------------------------------------------------------------------|----------|
| `storeName`    | `string`                          | Name of the collection to modify.                                 | Yes      |
| `newSchema`    | `SchemaDefinition<SchemaDefinitionType<U>>` | New schema definition for the collection.                | Yes      |
| `changeValues` | `Record<string, any>`             | Update operations to apply to existing documents.                 | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the schema is updated, or rejects with an error.

**Example:**

```javascript
const newSchema = {
  name: { type: String, required: true },
  email: { type: String, required: true },
  age: { type: Number, default: 0 },
};

await db.alterStore('users', newSchema, { $set: { age: 18 } });
console.log('Users schema updated');
```

#### findAndPopulateById

Retrieves documents by ID and populates specified fields.

**Signature:**

```javascript
async findAndPopulateById<T>(
  storeName: string,
  thingsToBePopulated: string | string[],
  query: Record<string, any>
): Promise<T[]>
```

**Parameters:**

| Parameter             | Type                    | Description                                              | Required |
|-----------------------|-------------------------|----------------------------------------------------------|----------|
| `storeName`           | `string`                | Name of the collection to query.                         | Yes      |
| `thingsToBePopulated` | `string | string[]`      | Field(s) to populate (e.g., `'posts'` or `['posts', 'comments']`). | Yes      |
| `query`               | `Record<string, any>`   | Query to filter documents (e.g., `{ _id: '123' }`).      | Yes      |

**Returns:**
- `Promise<T[]>`: An array of documents with populated fields.

**Example:**

```javascript
const user = await db.findAndPopulateById('users', 'posts', { _id: '123' });
console.log(user); // [{ name: 'John', posts: [{ title: 'Post 1', ... }, ...] }]
```

#### aggregate

Executes an aggregation pipeline on a collection.

**Signature:**

```javascript
async aggregate<T>(
  storeName: string,
  pipeline: any
): Promise<any[]>
```

**Parameters:**

| Parameter    | Type     | Description                                              | Required |
|--------------|----------|----------------------------------------------------------|----------|
| `storeName`  | `string` | Name of the collection to aggregate.                     | Yes      |
| `pipeline`   | `any`    | Array of aggregation pipeline stages.                    | Yes      |

**Returns:**
- `Promise<any[]>`: An array of aggregation results.

**Example:**

```javascript
const pipeline = [
  { $match: { name: 'John Doe' } },
  { $group: { _id: '$email', count: { $sum: 1 } } },
];

const results = await db.aggregate('users', pipeline);
console.log(results); // [{ _id: 'john@example.com', count: 1 }, ...]
```

#### pipelineBuilder

Creates an instance of `AggregationBuilder` for constructing aggregation pipelines.

**Signature:**

```javascript
pipelineBuilder(): AggregationBuilder
```

**Returns:**
- `AggregationBuilder`: An instance of the aggregation builder.

**Example:**

```javascript
const builder = db.pipelineBuilder();
const pipeline = builder
  .match('status', { eq: 'active' })
  .group('userId')
  .sum('amount', 'totalSpent')
  .build();

const results = await db.aggregate('orders', pipeline);
console.log(results);
```

#### createIndex

Creates an index on a specified column in a collection.

**Signature:**

```javascript
async createIndex(
  storeName: string,
  column: string,
  order: string,
  options: any
): Promise<void>
```

**Parameters:**

| Parameter   | Type     | Description                                              | Required |
|-------------|----------|----------------------------------------------------------|----------|
| `storeName` | `string` | Name of the collection to create the index on.           | Yes      |
| `column`    | `string` | Field to index (e.g., `'email'`).                        | Yes      |
| `order`     | `string` | Index order (e.g., `'1'` for ascending, `'-1'` for descending). | Yes      |
| `options`   | `any`    | Additional index options (e.g., `{ unique: true }`).     | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the index is created, or rejects with an error.

**Example:**

```javascript
await db.createIndex('users', 'email', '1', { unique: true });
console.log('Index created on email');
```

#### viewIndexes

Retrieves all indexes for a collection.

**Signature:**

```javascript
async viewIndexes(storeName: string): Promise<IndexDefinition[]>
```

**Parameters:**

| Parameter   | Type     | Description                                              | Required |
|-------------|----------|----------------------------------------------------------|----------|
| `storeName` | `string` | Name of the collection to view indexes for.              | Yes      |

**Returns:**
- `Promise<IndexDefinition[]>`: An array of index definitions.

**Example:**

```javascript
const indexes = await db.viewIndexes('users');
console.log(indexes); // [{ key: { email: 1 }, name: 'email_1', ... }, ...]
```

#### dropIndex

Drops a specified index from a collection.

**Signature:**

```javascript
async dropIndex(storeName: string, indexName: string): Promise<void>
```

**Parameters:**

| Parameter    | Type     | Description                                              | Required |
|--------------|----------|----------------------------------------------------------|----------|
| `storeName`  | `string` | Name of the collection to drop the index from.           | Yes      |
| `indexName`  | `string` | Name of the index to drop (e.g., `'email_1'`).           | Yes      |

**Returns:**
- `Promise<void>`: Resolves when the index is dropped, or rejects with an error.

**Example:**

```javascript
await db.dropIndex('users', 'email_1');
console.log('Index dropped');
```

#### findAndPopulateByKey

Retrieves documents from one collection and populates fields from another collection based on a key relationship.

**Signature:**

```javascript
async findAndPopulateByKey(
  fromStoreName: string,
  query: Record<string, any>,
  fromKey: string,
  findInStoreName: string,
  inKey: string
): Promise<any[]>
```

**Parameters:**

| Parameter         | Type                    | Description                                              | Required |
|-------------------|-------------------------|----------------------------------------------------------|----------|
| `fromStoreName`   | `string`                | Name of the source collection.                           | Yes      |
| `query`           | `Record<string, any>`   | Query to filter source documents.                        | Yes      |
| `fromKey`         | `string`                | Field in the source collection to match.                 | Yes      |
| `findInStoreName` | `string`                | Name of the collection to populate from.                 | Yes      |
| `inKey`           | `string`                | Field in the target collection to match against `fromKey`. | Yes      |

**Returns:**
- `Promise<any[]>`: An array of documents with populated fields.

**Example:**

```javascript
const users = await db.findAndPopulateByKey(
  'users',
  { name: 'John Doe' },
  'userId',
  'posts',
  'authorId'
);
console.log(users); // [{ name: 'John Doe', posts: [{ title: 'Post 1', ... }, ...] }]
```

#### startTransaction

Starts a new transaction session.

**Signature:**

```javascript
async startTransaction(): Promise<void>
```

**Returns:**
- `Promise<void>`: Resolves when the transaction session is started, or rejects with an error.

**Example:**

```javascript
await db.startTransaction();
console.log('Transaction started');
```

#### commitTransaction

Commits the current transaction.

**Signature:**

```javascript
async commitTransaction(): Promise<void>
```

**Returns:**
- `Promise<void>`: Resolves when the transaction is committed, or rejects with an error.

**Example:**

```javascript
await db.commitTransaction();
console.log('Transaction committed');
```

#### abortTransaction

Aborts the current transaction.

**Signature:**

```javascript
async abortTransaction(): Promise<void>
```

**Returns:**
- `Promise<void>`: Resolves when the transaction is aborted, or rejects with an error.

**Example:**

```javascript
await db.abortTransaction();
console.log('Transaction aborted');
```

#### getSession

Retrieves the current Mongoose session, if one exists.

**Signature:**

```javascript
async getSession(): Promise<mongoose.ClientSession | null>
```

**Returns:**
- `Promise<mongoose.ClientSession | null>`: The current session or `null` if no session exists.

**Example:**

```javascript
const session = await db.getSession();
if (session) {
  console.log('Active session retrieved');
} else {
  console.log('No active session');
}
```

#### getMongoose

Retrieves the Mongoose instance used by the wrapper.

**Signature:**

```javascript
async getMongoose(): Promise<typeof mongoose>
```

**Returns:**
- `Promise<typeof mongoose>`: The Mongoose instance.

**Example:**

```javascript
const mongoose = await db.getMongoose();
console.log('Mongoose instance retrieved:', mongoose.version);
```

#### disconnect

Closes the connection to the MongoDB database.

**Signature:**

```javascript
async disconnect(): Promise<void>
```

**Returns:**
- `Promise<void>`: Resolves when the connection is closed, or rejects with an error.

**Example:**

```javascript
await db.disconnect();
console.log('Database disconnected');
```

### AggregationBuilder Methods

The `AggregationBuilder` class simplifies MongoDB’s aggregation pipelines with a fluent, chainable API. It supports a comprehensive set of pipeline stages and operators, making complex data transformations accessible to beginners and powerful for advanced users. Below are the methods provided in the class, each with a description, parameters, and example.

#### match

Filters documents based on a field and condition, using a mapped operator (e.g., `eq`, `gt`) from `operatorMap`.

**Signature:**

```javascript
match(field: string, condition: Record<string, any>): this
```

**Parameters:**

| Parameter   | Type                    | Description                                              | Required |
|-------------|-------------------------|----------------------------------------------------------|----------|
| `field`     | `string`                | Field to filter on.                                      | Yes      |
| `condition` | `Record<string, any>`   | Condition object with operators (e.g., `{ eq: 'active' }`). | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .match('status', { eq: 'active' })
  .build();
```

#### group

Groups documents by a field or composite key, enabling accumulator operations.

**Signature:**

```javascript
group(groupBy: string | Record<string, any>): this
```

**Parameters:**

| Parameter  | Type                    | Description                                              | Required |
|------------|-------------------------|----------------------------------------------------------|----------|
| `groupBy`  | `string | Record<string, any>` | Field name or object for composite grouping key.         | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .build();
```

#### sum

Adds a `$sum` accumulator to the last group stage.

**Signature:**

```javascript
sum(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to sum.                                            | Yes      |
| `key`     | `string` | Output field name for the sum.                           | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .sum('amount', 'totalSpent')
  .build();
```

#### avg

Adds an `$avg` accumulator to the last group stage.

**Signature:**

```javascript
avg(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to average.                                        | Yes      |
| `key`     | `string` | Output field name for the average.                       | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .avg('score', 'averageScore')
  .build();
```

#### min

Adds a `$min` accumulator to the last group stage.

**Signature:**

```javascript
min(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to find the minimum of.                            | Yes      |
| `key`     | `string` | Output field name for the minimum.                       | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .min('price', 'minPrice')
  .build();
```

#### max

Adds a `$max` accumulator to the last group stage.

**Signature:**

```javascript
max(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to find the maximum of.                            | Yes      |
| `key`     | `string` | Output field name for the maximum.                       | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .max('price', 'maxPrice')
  .build();
```

#### first

Adds a `$first` accumulator to the last group stage.

**Signature:**

```javascript
first(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to select the first value of.                      | Yes      |
| `key`     | `string` | Output field name for the first value.                   | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .first('name', 'firstName')
  .build();
```

#### last

Adds a `$last` accumulator to the last group stage.

**Signature:**

```javascript
last(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to select the last value of.                       | Yes      |
| `key`     | `string` | Output field name for the last value.                    | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .last('name', 'lastName')
  .build();
```

#### push

Adds a `$push` accumulator to the last group stage, collecting values into an array.

**Signature:**

```javascript
push(field: string, key: string = field): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `field`   | `string` | Field to collect (or `'ENTIRE'` for the entire document). | Yes      |
| `key`     | `string` | Output field name for the array (defaults to `field`).   | No       |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .push('orderId', 'orders')
  .build();
```

#### addToSet

Adds an `$addToSet` accumulator to the last group stage, collecting unique values into an array.

**Signature:**

```javascript
addToSet(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to collect unique values from.                     | Yes      |
| `key`     | `string` | Output field name for the unique array.                  | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .addToSet('category', 'categories')
  .build();
```

#### stdDevPop

Adds a `$stdDevPop` accumulator to the last group stage for population standard deviation.

**Signature:**

```javascript
stdDevPop(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to calculate population standard deviation.        | Yes      |
| `key`     | `string` | Output field name for the result.                        | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .stdDevPop('score', 'scoreStdDevPop')
  .build();
```

#### stdDevSamp

Adds a `$stdDevSamp` accumulator to the last group stage for sample standard deviation.

**Signature:**

```javascript
stdDevSamp(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field to calculate sample standard deviation.            | Yes      |
| `key`     | `string` | Output field name for the result.                        | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .stdDevSamp('score', 'scoreStdDevSamp')
  .build();
```

#### mergeObjects

Adds a `$mergeObjects` accumulator to the last group stage to combine documents.

**Signature:**

```javascript
mergeObjects(value: string, key: string): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `value`   | `string` | Field containing objects to merge.                       | Yes      |
| `key`     | `string` | Output field name for the merged object.                 | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .mergeObjects('details', 'mergedDetails')
  .build();
```

#### count

Adds a `$sum: 1` accumulator to the last group stage to count documents.

**Signature:**

```javascript
count(key: string = 'count'): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `key`     | `string` | Output field name for the count (defaults to `'count'`). | No       |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .group('userId')
  .count('userCount')
  .build();
```

#### project

Specifies fields to include or exclude in the output.

**Signature:**

```javascript
project(projection: Record<string, any>): this
```

**Parameters:**

| Parameter    | Type                    | Description                                              | Required |
|--------------|-------------------------|----------------------------------------------------------|----------|
| `projection` | `Record<string, any>`   | Object specifying fields to include (1) or exclude (0).  | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .project({ name: 1, email: 1, _id: 0 })
  .build();
```

#### sort

Sorts documents by specified fields.

**Signature:**

```javascript
sort(sortFields: Record<string, 'asc' | 'desc'>): this
```

**Parameters:**

| Parameter     | Type                              | Description                                              | Required |
|---------------|-----------------------------------|----------------------------------------------------------|----------|
| `sortFields`  | `Record<string, 'asc' | 'desc'>` | Object mapping fields to sort direction (`asc` or `desc`). | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .sort({ totalSpent: 'desc' })
  .build();
```

#### limit

Limits the number of documents returned.

**Signature:**

```javascript
limit(n: number): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `n`       | `number` | Maximum number of documents to return.                   | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .limit(10)
  .build();
```

#### skip

Skips a specified number of documents.

**Signature:**

```javascript
skip(n: number): this
```

**Parameters:**

| Parameter | Type     | Description                                              | Required |
|-----------|----------|----------------------------------------------------------|----------|
| `n`       | `number` | Number of documents to skip.                             | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .skip(5)
  .build();
```

#### lookup

Performs a left outer join with another collection.

**Signature:**

```javascript
lookup(from: string, localField: string, foreignField: string, as: string): this
```

**Parameters:**

| Parameter      | Type     | Description                                              | Required |
|----------------|----------|----------------------------------------------------------|----------|
| `from`         | `string` | Name of the collection to join with.                     | Yes      |
| `localField`   | `string` | Field from the input documents.                          | Yes      |
| `foreignField` | `string` | Field from the `from` collection.                        | Yes      |
| `as`           | `string` | Name of the output array field.                          | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .lookup('posts', 'userId', 'authorId', 'userPosts')
  .build();
```

#### unset

Removes specified fields from documents.

**Signature:**

```javascript
unset(...fields: string[]): this
```

**Parameters:**

| Parameter | Type       | Description                                              | Required |
|-----------|------------|----------------------------------------------------------|----------|
| `fields`  | `string[]` | Fields to remove from documents.                         | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .unset('password', 'token')
  .build();
```

#### addFields

Adds new fields to documents.

**Signature:**

```javascript
addFields(fields: Record<string, any>): this
```

**Parameters:**

| Parameter | Type                    | Description                                              | Required |
|-----------|-------------------------|----------------------------------------------------------|----------|
| `fields`  | `Record<string, any>`   | Object specifying new fields and their values.           | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .addFields({ fullName: { $concat: ['$firstName', ' ', '$lastName'] } })
  .build();
```

#### replaceRoot

Replaces the document with a specified new root.

**Signature:**

```javascript
replaceRoot(newRoot: any): this
```

**Parameters:**

| Parameter  | Type     | Description                                              | Required |
|------------|----------|----------------------------------------------------------|----------|
| `newRoot`  | `any`    | Expression defining the new root document.               | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .replaceRoot('$details')
  .build();
```

#### replaceWith

Replaces the document with a specified value.

**Signature:**

```javascript
replaceWith(replacement: any): this
```

**Parameters:**

| Parameter     | Type     | Description                                              | Required |
|---------------|----------|----------------------------------------------------------|----------|
| `replacement` | `any`    | Expression defining the replacement document.            | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .replaceWith('$details')
  .build();
```

#### graphLookup

Performs a recursive search on a collection.

**Signature:**

```javascript
graphLookup(options: {
  from: string;
  startWith: any;
  connectFromField: string;
  connectToField: string;
  as: string;
  maxDepth?: number;
  depthField?: string;
  restrictSearchWithMatch?: Record<string, any>;
}): this
```

**Parameters:**

| Parameter                  | Type                    | Description                                              | Required |
|----------------------------|-------------------------|----------------------------------------------------------|----------|
| `options.from`             | `string`                | Collection to perform the lookup on.                     | Yes      |
| `options.startWith`        | `any`                   | Expression to start the graph lookup.                    | Yes      |
| `options.connectFromField` | `string`                | Field to connect from.                                   | Yes      |
| `options.connectToField`   | `string`                | Field to connect to.                                     | Yes      |
| `options.as`               | `string`                | Output array field name.                                 | Yes      |
| `options.maxDepth`         | `number`                | Maximum recursion depth (optional).                      | No       |
| `options.depthField`       | `string`                | Field to store depth (optional).                         | No       |
| `options.restrictSearchWithMatch` | `Record<string, any>` | Match conditions to restrict search (optional).          | No       |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .graphLookup({
    from: 'employees',
    startWith: '$managerId',
    connectFromField: 'managerId',
    connectToField: '_id',
    as: 'reportingHierarchy',
  })
  .build();
```

#### unwind

Deconstructs an array field into multiple documents.

**Signature:**

```javascript
unwind(field: string | Record<string, any>): this
```

**Parameters:**

| Parameter | Type                    | Description                                              | Required |
|-----------|-------------------------|----------------------------------------------------------|----------|
| `field`   | `string | Record<string, any>` | Field to unwind or unwind options object.                | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .unwind('items')
  .build();
```

#### bucket

Groups documents into buckets based on a specified expression.

**Signature:**

```javascript
bucket(options: {
  groupBy: any;
  boundaries: any[];
  default?: any;
  output: Record<string, any>;
}): this
```

**Parameters:**

| Parameter           | Type                    | Description                                              | Required |
|---------------------|-------------------------|----------------------------------------------------------|----------|
| `options.groupBy`   | `any`                   | Expression to group by.                                  | Yes      |
| `options.boundaries`| `any[]`                 | Array of bucket boundaries.                              | Yes      |
| `options.default`   | `any`                   | Default bucket for non-matching documents (optional).    | No       |
| `options.output`    | `Record<string, any>`   | Output specification for each bucket.                    | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .bucket({
    groupBy: '$price',
    boundaries: [0, 100, 200, 300],
    default: 'other',
    output: { count: { $sum: 1 } },
  })
  .build();
```

#### bucketAuto

Automatically groups documents into a specified number of buckets.

**Signature:**

```javascript
bucketAuto(options: {
  groupBy: any;
  buckets: number;
  output?: Record<string, any>;
  granularity?: string;
}): this
```

**Parameters:**

| Parameter            | Type                    | Description                                              | Required |
|----------------------|-------------------------|----------------------------------------------------------|----------|
| `options.groupBy`    | `any`                   | Expression to group by.                                  | Yes      |
| `options.buckets`    | `number`                | Number of buckets.                                       | Yes      |
| `options.output`     | `Record<string, any>`   | Output specification for each bucket (optional).         | No       |
| `options.granularity`| `string`                | Granularity for numeric bucketing (optional).            | No       |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .bucketAuto({
    groupBy: '$price',
    buckets: 5,
    output: { count: { $sum: 1 } },
  })
  .build();
```

#### facet

Processes multiple aggregation pipelines within a single stage.

**Signature:**

```javascript
facet(facets: Record<string, any[]>): this
```

**Parameters:**

| Parameter | Type                    | Description                                              | Required |
|-----------|-------------------------|----------------------------------------------------------|----------|
| `facets`  | `Record<string, any[]>` | Object mapping facet names to pipeline arrays.           | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .facet({
    byCategory: [{ $group: { _id: '$category', count: { $sum: 1 } } }],
    byPrice: [{ $bucket: { groupBy: '$price', boundaries: [0, 100, 200] } }],
  })
  .build();
```

#### merge

Writes the results of the pipeline to a collection.

**Signature:**

```javascript
merge(options: string | Record<string, any>): this
```

**Parameters:**

| Parameter | Type                    | Description                                              | Required |
|-----------|-------------------------|----------------------------------------------------------|----------|
| `options` | `string | Record<string, any>` | Collection name or merge options object.                 | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .merge('outputCollection')
  .build();
```

#### out

Writes the pipeline results to a collection, replacing its contents.

**Signature:**

```javascript
out(collectionName: string): this
```

**Parameters:**

| Parameter        | Type     | Description                                              | Required |
|------------------|----------|----------------------------------------------------------|----------|
| `collectionName` | `string` | Name of the collection to write to.                      | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .out('results')
  .build();
```

#### search

Adds a `$search` stage for Atlas Search.

**Signature:**

```javascript
search(searchStage: Record<string, any>): this
```

**Parameters:**

| Parameter     | Type                    | Description                                              | Required |
|---------------|-------------------------|----------------------------------------------------------|----------|
| `searchStage` | `Record<string, any>`   | Search stage configuration.                              | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .search({ text: { query: 'example', path: 'description' } })
  .build();
```

#### searchMeta

Adds a `$searchMeta` stage for Atlas Search metadata.

**Signature:**

```javascript
searchMeta(searchStage: Record<string, any>): this
```

**Parameters:**

| Parameter     | Type                    | Description                                              | Required |
|---------------|-------------------------|----------------------------------------------------------|----------|
| `searchStage` | `Record<string, any>`   | Search metadata stage configuration.                     | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .searchMeta({ count: { type: 'total' } })
  .build();
```

#### redact

Restricts document content based on an expression.

**Signature:**

```javascript
redact(expression: any): this
```

**Parameters:**

| Parameter    | Type     | Description                                              | Required |
|--------------|----------|----------------------------------------------------------|----------|
| `expression` | `any`    | Redaction expression (e.g., `$cond`).                    | Yes      |

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .redact({
    $cond: { if: { $eq: ['$level', 'public'] }, then: '$$KEEP', else: '$$PRUNE' },
  })
  .build();
```

#### indexStats

Adds an `$indexStats` stage to retrieve index statistics.

**Signature:**

```javascript
indexStats(): this
```

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .indexStats()
  .build();
```

#### currentOp

Adds a `$currentOp` stage to retrieve current operations.

**Signature:**

```javascript
currentOp(): this
```

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .currentOp()
  .build();
```

#### collStats

Adds a `$collStats` stage to retrieve collection statistics.

**Signature:**

```javascript
collStats(): this
```

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .collStats()
  .build();
```

#### planCacheStats

Adds a `$planCacheStats` stage to retrieve query plan cache statistics.

**Signature:**

```javascript
planCacheStats(): this
```

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .planCacheStats()
  .build();
```

#### listSessions

Adds a `$listSessions` stage to retrieve active sessions.

**Signature:**

```javascript
listSessions(): this
```

**Returns:**
- `this`: The `AggregationBuilder` instance for chaining.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .listSessions()
  .build();
```

#### build

Returns the constructed aggregation pipeline.

**Signature:**

```javascript
build(): any[]
```

**Returns:**
- `any[]`: The array of pipeline stages.

**Example:**

```javascript
const pipeline = db.pipelineBuilder()
  .match('status', { eq: 'active' })
  .group('userId')
  .sum('amount', 'totalSpent')
  .build();
console.log(pipeline); // [{ $match: ... }, { $group: ... }]
```

## Advanced Usage

Mongo-Bolt supports advanced MongoDB features, making it suitable for complex applications. The following sections, inspired by Hashnode Docs’ focus on interactivity, provide guidance on leveraging these capabilities.

### Transaction Management

Mongo-Bolt supports MongoDB transactions for atomic operations across multiple collections. Use `startTransaction`, `commitTransaction`, `abortTransaction`, and `getSession` to manage transactions.

**Example:**

```javascript
const db = new MongoDB(config);
await db.connect();

try {
  await db.startTransaction();

  const session = await db.getSession();
  const user = { name: 'Alice', email: 'alice@example.com' };
  await db.insertItem('users', user, { session });

  const post = { title: 'First Post', author: 'Alice' };
  await db.insertItem('posts', post, { session });

  await db.commitTransaction();
  console.log('Transaction committed');
} catch (error) {
  await db.abortTransaction();
  console.error('Transaction aborted:', error.message);
} finally {
  await db.disconnect();
}
```

### Aggregation Pipelines

The `aggregate` method and `AggregationBuilder` enable powerful data aggregation. The `AggregationBuilder` provides a fluent interface, simplifying complex pipelines.

**Example:**

```javascript
const builder = db.pipelineBuilder();
const pipeline = builder
  .match('status', { eq: 'active' })
  .group('userId')
  .sum('amount', 'totalSpent')
  .sort({ totalSpent: 'desc' })
  .limit(10)
  .build();

const topSpenders = await db.aggregate('orders', pipeline);
console.log(topSpenders);
```

### Index Management

Indexes optimize query performance. Use `createIndex`, `viewIndexes`, and `dropIndex` to manage indexes.

**Example:**

```javascript
// Create a unique index
await db.createIndex('users', 'email', '1', { unique: true });

// View all indexes
const indexes = await db.viewIndexes('users');
console.log(indexes);

// Drop an index
await db.dropIndex('users', 'email_1');
console.log('Index dropped');
```

## Examples

The following examples demonstrate Mongo-Bolt’s capabilities in real-world scenarios, designed to be interactive and clear, as inspired by Hashnode Docs.

### Complete CRUD Workflow

This example shows a full CRUD workflow, from creating a collection to deleting a document.

```javascript
import MongoDB from 'mongo-bolt';
import { Schema } from 'mongoose';

const config = {
  uri: 'mongodb://localhost:27017/mydb',
  options: { useNewUrlParser: true, useUnifiedTopology: true },
};

const db = new MongoDB(config);

async function run() {
  try {
    // Connect to database
    await db.connect();

    // Create a collection
    const userSchema = {
      name: { type: String, required: true },
      email: { type: String, required: true },
    };
    await db.createStore('users', userSchema);

    // Insert a document
    await db.insertItem('users', { name: 'Alice', email: 'alice@example.com' });

    // Find documents
    const users = await db.findItem('users', { name: 'Alice' });
    console.log(users);

    // Update documents
    await db.updateItems('users', { name: 'Alice' }, { $set: { email: 'alice.new@example.com' } });

    // Delete a document
    await db.dropItem('users', { email: 'alice.new@example.com' });

    // Disconnect
    await db.disconnect();
  } catch (error) {
    console.error('Error:', error.message);
  }
}

run();
```

### Populating Related Data

This example demonstrates how to populate related data across collections.

```javascript
import MongoDB from 'mongo-bolt';
import { Schema } from 'mongoose';

const userSchema = {
  name: { type: String, required: true },
  postIds: [{ type: Schema.Types.ObjectId, ref: 'posts' }],
};

const postSchema = {
  title: { type: String, required: true },
  authorId: { type: Schema.Types.ObjectId, ref: 'users' },
};

const db = new MongoDB(config);
await db.connect();
await db.createStore('users', userSchema);
await db.createStore('posts', postSchema);

const users = await db.findAndPopulateById('users', 'postIds', { name: 'John' });
console.log(users); // [{ name: 'John', postIds: [{ title: 'Post 1', ... }, ...] }]
await db.disconnect();
```

### Building an Aggregation Pipeline

This example shows how to use `AggregationBuilder` for advanced data analysis.

```javascript
const builder = db.pipelineBuilder();
const pipeline = builder
  .match('status', { eq: 'active' })
  .group('category')
  .sum('price', 'total')
  .sort({ total: 'desc' })
  .limit(5)
  .build();

const results = await db.aggregate('products', pipeline);
console.log(results); // [{ _id: 'electronics', total: 5000 }, ...]
```

## Error Handling

Mongo-Bolt methods throw errors for invalid states (e.g., uninitialized connector) or database issues. Use try-catch blocks to handle errors, as recommended in robust documentation like Hashnode Docs.

**Example:**

```javascript
try {
  await db.insertItem('users', { name: 'Invalid User' });
} catch (error) {
  console.error('Failed to insert user:', error.message);
}
```

## Contributing

Contributions to Mongo-Bolt are welcome! To contribute:

1. Fork the repository on GitHub.
2. Create a feature branch (`git checkout -b feature/your-feature`).
3. Commit your changes (`git commit -m 'Add your feature'`).
4. Push to the branch (`git push origin feature/your-feature`).
5. Open a pull request.

Please include tests and update documentation for new features, aligning with the collaborative workflows emphasized by Hashnode Docs.

## License

MIT License. See [LICENSE](LICENSE) for details.