mongo-pipeliner
Version:
A practical and userful set of tools to help you build and test MongoDB aggregation pipelines.
157 lines (109 loc) • 5.17 kB
Markdown
# Mongoose Aggregation Pipeline Builder

As aggregation queries become increasingly complex, maintaining and understanding these structures can become challenging. This package addresses this issue by providing a fluid and flexible interface for building aggregation pipelines.
`mongoose-pipeliner` offers a class and interface that can be used as an aggregation pipeline builder or extended to construct a customized builder. This tool is intended to significantly simplify the process of building and maintaining complex aggregation queries.
## Features
- Simplification of Complex Queries: Facilitates the construction of complex aggregation pipelines.
- Design Patterns: Implements Builder and Template patterns for enhanced flexibility.
- Function Chaining: Enables a more readable and maintainable query building approach.
- Aggregation Operations: Supports all basic MongoDB aggregation operations and some advanced ones like lookup, set, unset, unwind, etc.
- Customization and Extensibility: Allows users to extend and customize the builder according to their specific needs.
## Installation
```bash
npm install mongoose-pipeliner
```
## Usage
Inject pipeline stages using the builder's methods. The builder will automatically add the stages to the pipeline in the order they are injected.
```typescript
const { User } from './models';
const { AggregationPipelineBuilder } from 'mongoose-pipeliner';
const builder = new AggregationPipelineBuilder();
builder.filter({ status: 'active' }).project({ name: 1, status: 1 }).limit(10);
const pipeline = builder.assemble();
// Use your pipeline with your Mongoose model
User.aggregation(pipeline).exec((err, result) => {
// ...
});
```
You can perform aggregation operations directly from builder class.
```typescript
const { User } from './models';
const { AggregationPipelineBuilder } from 'mongoose-pipeliner';
const builder = new AggregationPipelineBuilder(User);
builder.filter({ status: 'active' }).project({ name: 1, status: 1 }).limit(10);
const result = await builder.execute();
```
## Implementation Strategies
Some useful implementation strategies to implement a `pipeline-builder` is to group operations that can be reused by multiple components or services through the template class strategy or inheritance.
```ts
import { AggregationPipelineBuilder } from 'mongoose-pipeliner';
import { User } from './models';
class MyCustomUserPipelineBuilder extends AggregationPipelineBuilder {
myCustomOperation() {
return this.filter({ status: 'active' }).project({ name: 1, status: 1 }).limit(10).skip().execute();
}
}
// Use your pipeline with your Mongoose model
const result = await new MyCustomUserPipelineBuilder(User).myCustomOperation();
```
or
```ts
import { AggregationPipelineBuilder } from 'mongoose-pipeliner';
import { User } from './models';
class MyCustomUserPipelineBuilder extends AggregationPipelineBuilder {
searchActive() {
return this.filter({ status: 'active' }).project({ name: 1, status: 1 });
}
searchInactive() {
return this.filter({ status: 'inactive' }).project({ name: 1, status: 1 });
}
standardPagination(limit: number = 10, page: number = 1) {
return this.paginate(limit, page);
}
}
// Use your pipeline with your Mongoose model
const builder = await new MyCustomUserPipelineBuilder(User);
const first_search = builder.searchActive().standardPagination(10, 2).execute();
const second_search = builder.searchInactive().standardPagination(10, 2).execute();
```
Or simply define a `pipeline-builder` as part of a utility class, service or component
that can be consumed or implemented throughout your application.
```ts
import { AggregationPipelineBuilder } from 'mongoose-pipeliner';
import { User } from './models';
/**
* @description Provide custom pipelines to be injected
* in some aggregation pipeline repository
*/
class UserPipelineProvider {
protected static builder = new AggregationPipelineBuilder(User);
static activePipeline() {
return builder.filter({ status: 'active' }).project({ name: 1, status: 1 }).assemble();
}
static inactivePipeline() {
return builder.filter({ status: 'inactive' }).project({ name: 1, status: 1 }).assemble();
}
static someComplexPipeline() {
return [].concat(this.activePipeline() /* my custom proxy pipeline */);
}
}
// Implement the provider class
class UserRepository {
async findActiveUsers() {
return User.aggregation(UserPipelineProvider.activePipeline()).exec();
}
async findInactiveUsers() {
return User.aggregation(UserPipelineProvider.inactivePipeline()).exec();
}
async findSomeComplexUsers() {
return User.aggregation(UserPipelineProvider.someComplexPipeline()).exec();
}
}
```
## Contributing
Contributions are welcome. If you have ideas for improving this package, please read our contribution guide.
1. Fork the repository.
2. Create a new branch for each feature or improvement.
3. Submit a pull request with your changes.
## License
This project is licensed under MIT License - [Visit the license document](./LICENSE) file for details.