mongo-bolt
Version:
A lightweight, beginner-friendly MongoDB wrapper with inbuilt caching and simplified joins/indexing.
1,773 lines (1,256 loc) • 58.9 kB
Markdown
# 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' } })