Skip to main content

Command Palette

Search for a command to run...

MongoBolt

Published
13 min readView as Markdown
A

I am Aryan Mankame, SDE-2 at Deutsche Bank CSE 2024 Batch passout at Maulana Azad National Institute of Technology, Bhopal. With a strong passion for technology and a focus on full stack development, I possess a diverse skill set that includes: Frontend: React.js: I am proficient in building captivating and interactive user interfaces using React.js, ensuring a seamless user experience. Redux.js: I am adept at utilizing Redux.js for efficient state management, enabling smooth data flow within applications. HTML5 & CSS3: I have a keen eye for crafting visually appealing and responsive web pages using the latest HTML5 and CSS3 techniques. Backend: Node.js & Express.js: With expertise in Node.js and Express.js, I develop scalable and robust server-side applications. RESTful APIs: I am skilled in designing and implementing RESTful APIs that facilitate seamless communication between frontend and backend systems. Database: MongoDB, Firebase, PostgreSQL, MySQL: I have hands-on experience working with both SQL and NoSQL databases, ensuring efficient data storage and retrieval. My commitment to innovation and problem-solving has been demonstrated through my active participation in various hackathons. Notable achievements include securing the 2nd Runners up position in Wittyhacks 3.0, attaining the 7th position in the Ecell NITB Hackathon, and ranking among the top 15 participants in BitsHackathon. Driven by a desire to make a meaningful impact in the field of technology, my goal is to leverage my skills and enthusiasm to contribute to cutting-edge projects and drive the advancement of software development. Overall, I am a talented and dedicated full stack developer with a proven track record in both frontend and backend technologies. My strong technical foundation, coupled with my passion for innovation, positions me as an invaluable asset to any software development team.

MongoDB Wrapper

A lightweight, modern MongoDB wrapper built on top of Mongoose, designed to simplify database operations with a clean and intuitive API. This package provides a robust interface for connecting to MongoDB, managing collections, performing CRUD operations, handling transactions, building aggregation pipelines, and managing indexes, making it ideal for Node.js applications.

Table of Contents

Installation

Install the package via npm:

npm install mongodb-wrapper

Ensure Mongoose is installed, as it is a peer dependency:

npm install mongoose

Getting Started

To use the MongoDB wrapper, import the MongoDB class, configure it with your MongoDB connection details, and establish a connection.

import MongoDB from 'mongodb-wrapper';

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);
  }
}

init();

Configuration

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

PropertyTypeDescriptionRequired
uristringMongoDB connection URI (e.g., mongodb://localhost:27017/mydb)Yes
optionsobjectMongoose connection options (e.g., { useNewUrlParser: true })No

Example:

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

Methods

connect

Establishes a connection to the MongoDB database using the provided configuration.

Signature:

async connect(): Promise<void>

Returns:

  • Promise<void>: Resolves when the connection is successful, or rejects with an error if the connection fails.

Example:

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

createStore

Creates a new collection with a specified schema.

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
collectionNamestringName of the collection to create.Yes
schemaSchemaDefinition<SchemaDefinitionType<T>>Mongoose schema definition for the collection.Yes

Returns:

  • Promise<void>: Resolves when the collection is created, or rejects with an error.

Example:

(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:

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

Parameters:

ParameterTypeDescriptionRequired
collectionNamestringName of the collection to insert into.Yes
documentDataTThe document data to insert.Yes

Returns:

  • Promise<void>: Resolves when the document is inserted, or rejects with an error.

Example:

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:

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

Parameters:

ParameterTypeDescriptionRequired
collectionNamestringName of the collection to insert into.Yes
documentsDataT[]Array of document data to insert.Yes

Returns:

  • Promise<void>: Resolves when all documents are inserted, or rejects with an error.

Example:

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:

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

Parameters:

ParameterTypeDescriptionRequired
collectionNamestringName of the collection to query.Yes
queryRecord<string, any>Query object to filter documents (default: {}).No

Returns:

  • Promise<T[]>: An array of documents matching the query.

Example:

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:

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

Parameters:

ParameterTypeDescriptionRequired
collectionNamestringName of the collection to update.Yes
queryRecord<string, any>Query to select documents to update.Yes
updateRecord<string, any>Update operations to apply (e.g., { $set: { ... } }).Yes

Returns:

  • Promise<number>: The number of documents updated.

Example:

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:

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

Parameters:

ParameterTypeDescriptionRequired
collectionNamestringName of the collection to delete.Yes

Returns:

  • Promise<void>: Resolves when the collection is deleted, or rejects with an error.

Example:

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

dropItem

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

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to delete from.Yes
itemInfoRecord<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:

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

dropItems

Deletes multiple documents from a collection based on a query.

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to delete from.Yes
itemInfoRecord<string, any>Query to identify documents to delete.Yes

Returns:

  • Promise<void>: Resolves when the documents are deleted, or rejects with an error.

Example:

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

truncateStore

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

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to truncate.Yes

Returns:

  • Promise<void>: Resolves when the collection is truncated, or rejects with an error.

Example:

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

alterStore

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

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to modify.Yes
newSchemaSchemaDefinition<SchemaDefinitionType<U>>New schema definition for the collection.Yes
changeValuesRecord<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:

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:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to query.Yes
thingsToBePopulated`stringstring[]`Field(s) to populate (e.g., 'posts' or ['posts', 'comments']).
queryRecord<string, any>Query to filter documents (e.g., { _id: '123' }).Yes

Returns:

  • Promise<T[]>: An array of documents with populated fields.

Example:

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:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to aggregate.Yes
pipelineanyArray of aggregation pipeline stages.Yes

Returns:

  • Promise<any[]>: An array of aggregation results.

Example:

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:

pipelineBuilder(): AggregationBuilder

Returns:

  • AggregationBuilder: An instance of the aggregation builder.

Example:

const builder = db.pipelineBuilder();
const pipeline = builder
  .match({ name: 'John Doe' })
  .group({ _id: '$email', count: { $sum: 1 } })
  .build();

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

createIndex

Creates an index on a specified column in a collection.

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to create the index on.Yes
columnstringField to index (e.g., 'email').Yes
orderstringIndex order (e.g., '1' for ascending, '-1' for descending).Yes
optionsanyAdditional index options (e.g., { unique: true }).Yes

Returns:

  • Promise<void>: Resolves when the index is created, or rejects with an error.

Example:

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

viewIndexes

Retrieves all indexes for a collection.

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to view indexes for.Yes

Returns:

  • Promise<IndexDefinition[]>: An array of index definitions.

Example:

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

dropIndex

Drops a specified index from a collection.

Signature:

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

Parameters:

ParameterTypeDescriptionRequired
storeNamestringName of the collection to drop the index from.Yes
indexNamestringName 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:

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:

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

Parameters:

ParameterTypeDescriptionRequired
fromStoreNamestringName of the source collection.Yes
queryRecord<string, any>Query to filter source documents.Yes
fromKeystringField in the source collection to match.Yes
findInStoreNamestringName of the collection to populate from.Yes
inKeystringField in the target collection to match against fromKey.Yes

Returns:

  • Promise<any[]>: An array of documents with populated fields.

Example:

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:

async startTransaction(): Promise<void>

Returns:

  • Promise<void>: Resolves when the transaction session is started, or rejects with an error.

Example:

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

commitTransaction

Commits the current transaction.

Signature:

async commitTransaction(): Promise<void>

Returns:

  • Promise<void>: Resolves when the transaction is committed, or rejects with an error.

Example:

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

abortTransaction

Aborts the current transaction.

Signature:

async abortTransaction(): Promise<void>

Returns:

  • Promise<void>: Resolves when the transaction is aborted, or rejects with an error.

Example:

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

getSession

Retrieves the current Mongoose session, if one exists.

Signature:

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

Returns:

  • Promise<mongoose.ClientSession | null>: The current session or null if no session exists.

Example:

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:

async getMongoose(): Promise<typeof mongoose>

Returns:

  • Promise<typeof mongoose>: The Mongoose instance.

Example:

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

disconnect

Closes the connection to the MongoDB database.

Signature:

async disconnect(): Promise<void>

Returns:

  • Promise<void>: Resolves when the connection is closed, or rejects with an error.

Example:

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

Advanced Usage

Transaction Management

The wrapper supports MongoDB transactions for atomic operations across multiple collections. Use startTransaction, commitTransaction, and abortTransaction to manage transactions, and getSession to access the session for custom operations.

Example:

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

try {
  await db.startTransaction();

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

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

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

Aggregation Pipelines

The aggregate method and pipelineBuilder provide powerful tools for data aggregation. The pipelineBuilder offers a fluent interface for constructing pipelines.

Example:

const builder = db.pipelineBuilder();
const pipeline = builder
  .match\(\)match({ status: 'active' })
  .group({ _id: '$userId', totalSpent: { $sum: '$amount' } })
  .sort({ totalSpent: -1 })
  .limit(10)
  .build();

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

Index Management

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

Example:

// 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');

Examples

Complete CRUD Workflow

import MongoDB from 'mongodb-wrapper';
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);
  }
}

run();
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' },
};

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', ... }, ...] }]

Error Handling

All methods throw errors if the database connection is not established or if invalid parameters are provided. Use try-catch blocks to handle errors gracefully:

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

License

MIT License. See LICENSE for details.