Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
MongoSense is a flexible and easy-to-use MongoDB aggregation pipeline builder with IntelliOptimizer for performance-first query optimization.
MongoSense is a flexible and easy-to-use MongoDB aggregation pipeline builder. It supports chaining, conditional stage inclusion, logging for debugging purposes, and advanced query optimization via the IntelliOptimizer engine. Build complex pipelines easily with methods that map directly to MongoDB’s aggregation framework while optimizing performance.
null
or undefined
).debugMode
to log the pipeline construction process for debugging.IntelliOptimizer
engine provides performance enhancements, including:
npm install mongosense
The MongoSense()
function is a factory that creates and returns an instance of the MongoSenseQueryBuilder
class. This builder provides a flexible way to construct MongoDB aggregation pipelines using chained methods.
The MongoSenseQueryBuilder
class provides the following key methods:
collection()
: Select one or more collections.match()
: Add a $match
stage to filter documents.sort()
: Add a $sort
stage to order documents.limit()
: Add a $limit
stage to restrict the number of documents.skip()
: Add a $skip
stage to skip a number of documents.lookup()
: Add a $lookup
stage for left outer joins.addFields()
, $bucket()
, $bucketAuto()
, $count()
, $facet()
, $project()
, $unwind()
, $out()
, $replaceRoot()
, $merge()
, $redact()
, $sample()
.import { MongoSense } from 'mongosense';
const builder = new MongoSense(true) // Enable debug mode
.collection('users')
.match({ isActive: true }) // Add $match stage
.addFields({ fullName: { $concat: ['$firstName', ' ', '$lastName'] } }) // Add $addFields stage
.project({ firstName: 1, lastName: 1, fullName: 1 }) // Add $project stage
.unwind('$orders') // Add $unwind stage
.count('orderCount') // Add $count stage
.sample(10) // Add $sample stage
.build();
console.log(builder);
{
"pipeline": [
{ "$match": { "isActive": true } },
{ "$addFields": { "fullName": { "$concat": ["$firstName", " ", "$lastName"] } } },
{ "$project": { "firstName": 1, "lastName": 1, "fullName": 1 } },
{ "$unwind": "$orders" },
{ "$count": "orderCount" },
{ "$sample": { "size": 10 } }
],
"collections": ["users"]
}
MongoSense(debugMode: boolean = false)
Creates a new instance of the MongoSenseQueryBuilder.
debugMode
: When set to true
, enables logging of pipeline construction. Default is false
.The collection()
method allows you to specify one or more MongoDB collections that the query will target. This is useful for operations like $lookup
or for multi-collection queries.
// Example: Single Collection
const builder = MongoSense().collection('users');
// Example: Multiple Collections
const builder = MongoSense().collection('users', 'orders');
You can also chain the collection selector with other methods, as shown:
const pipeline = MongoSense()
.collection('users')
.build();
The match()
method is used to add a $match
stage to the MongoDB aggregation pipeline. It allows you to filter documents based on a given set of criteria.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.match({ isActive: true }) // Filter for active users
.build();
console.log(pipeline);
// Output:
// [
// { $match: { isActive: true } }
// ]
The sort()
method is used to add a $sort
stage to the MongoDB aggregation pipeline. It allows you to sort documents based on specific fields in either ascending or descending order.
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.match({ isActive: true }) // Filter for active users
.sort({ age: 1 }) // Sort by age in ascending order
.build();
console.log(pipeline);
// Output:
// [
// { $match: { isActive: true } },
// { $sort: { age: 1 } }
// ]
The limit()
and skip()
methods are used to add $limit
and $skip
stages to the MongoDB aggregation pipeline. These stages are essential for pagination, where skip()
is used to skip a certain number of documents and limit()
is used to return a limited number of documents.
// Example:
const pageSize = 10;
const pageNumber = 3; // For page 3
const skip = (pageNumber - 1) * pageSize;
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.skip(skip) // Skip the first 20 documents (for page 3)
.limit(pageSize) // Return 10 documents
.build();
console.log(pipeline);
// Output:
// [
// { $skip: 20 },
// { $limit: 10 }
// ]
When implementing pagination, you typically calculate how many documents to skip based on the current page number and the page size (number of items per page). Here's the formula:
The lookup()
method is used to add a $lookup
stage to the MongoDB aggregation pipeline. This stage performs a left outer join with another collection, allowing you to merge documents from two collections.
// Example:
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.lookup('orders', '_id', 'userId', 'userOrders') // Join with the 'orders' collection
.build();
console.log(pipeline);
// Output:
// [
// {
// $lookup: {
// from: 'orders',
// localField: '_id',
// foreignField: 'userId',
// as: 'userOrders'
// }
// }
// ]
The group()
method is used to add a $group
stage to the MongoDB aggregation pipeline. This stage allows you to group documents by a specified key and perform various aggregation operations, such as $sum
, $avg
, $min
, and $max
.
// Example:
const pipeline = MongoSense()
.collection('sales') // Select the 'sales' collection
.group({ category: "$category" }, { totalSales: { $sum: "$amount" } }) // Group by category and sum total sales
.build();
console.log(pipeline);
// Output:
// [
// {
// $group: {
// _id: { category: "$category" },
// totalSales: { $sum: "$amount" }
// }
// }
// ]
The addFields()
method is used to add new fields to documents in the MongoDB aggregation pipeline.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.addFields({ fullName: { $concat: ['$firstName', ' ', '$lastName'] } }) // Add a fullName field
.build();
console.log(pipeline);
// Output:
// [
// { $addFields: { fullName: { $concat: ['$firstName', ' ', '$lastName'] } } }
// ]
fields
: An object defining the new fields to add.The bucket()
method is used to group documents into user-defined buckets based on a specified field.
// Example
const pipeline = MongoSense()
.collection('sales') // Select the 'sales' collection
.bucket({
groupBy: "$amount",
boundaries: [0, 100, 200, 300, 400],
default: "Other",
output: {
count: { $sum: 1 },
totalAmount: { $sum: "$amount" }
}
}) // Group sales by amount
.build();
console.log(pipeline);
// Output:
// [
// { $bucket: { groupBy: "$amount", boundaries: [0, 100, 200, 300, 400], default: "Other", output: { count: { $sum: 1 }, totalAmount: { $sum: "$amount" } } } }
// ]
bucketSpec
: The bucket specification object.The bucketAuto()
method is used to automatically group documents into a specified number of buckets based on a field.
// Example
const pipeline = MongoSense()
.collection('sales') // Select the 'sales' collection
.bucketAuto({
groupBy: "$amount",
buckets: 4,
output: {
count: { $sum: 1 },
totalAmount: { $sum: "$amount" }
}
}) // Automatically group sales into 4 buckets
.build();
console.log(pipeline);
// Output:
// [
// { $bucketAuto: { groupBy: "$amount", buckets: 4, output: { count: { $sum: 1 }, totalAmount: { $sum: "$amount" } } } }
// ]
bucketAutoSpec
: The auto bucket specification object.The count()
method is used to count the number of documents that pass through the pipeline.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.count('userCount') // Count the number of users
.build();
console.log(pipeline);
// Output:
// [
// { $count: "userCount" }
// ]
field
: The name of the field where the count will be stored.The facet()
method is used to run multiple aggregation pipelines in parallel and merge the results.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.facet({
ageFacet: [
{ $match: { age: { $gte: 18 } } },
{ $count: "adultCount" }
],
locationFacet: [
{ $match: { location: { $exists: true } } },
{ $count: "locationCount" }
]
}) // Run two pipelines: one to count adults, one to count users with locations
.build();
console.log(pipeline);
// Output:
// [
// { $facet: { ageFacet: [{ $match: { age: { $gte: 18 } } }, { $count: "adultCount" }], locationFacet: [{ $match: { location: { $exists: true } } }, { $count: "locationCount" }] } }
// ]
facetSpec
: An object containing multiple pipelines to run in parallel.The project()
method is used to include, exclude, or add new fields to documents in the MongoDB aggregation pipeline.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.project({ firstName: 1, lastName: 1, fullName: { $concat: ['$firstName', ' ', '$lastName'] } }) // Include fullName field
.build();
console.log(pipeline);
// Output:
// [
// { $project: { firstName: 1, lastName: 1, fullName: { $concat: ['$firstName', ' ', '$lastName'] } } }
// ]
projection
: An object specifying the fields to include, exclude, or compute.The unwind()
method is used to deconstruct an array field into separate documents.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.unwind('$orders') // Unwind the 'orders' array field
.build();
console.log(pipeline);
// Output:
// [
// { $unwind: "$orders" }
// ]
path
: The path to the array field to unwind.options
: Additional unwind options (optional).The out()
method is used to write the results of the pipeline to a specified collection.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.out('usersArchive') // Write the output to the 'usersArchive' collection
.build();
console.log(pipeline);
// Output:
// [
// { $out: "usersArchive" }
// ]
collection
: The name of the collection to output the results to.The replaceRoot()
method is used to replace the root document with a new document.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.replaceRoot({ newRoot: "$contactInfo" }) // Replace root with the 'contactInfo' document
.build();
console.log(pipeline);
// Output:
// [
// { $replaceRoot: { newRoot: "$contactInfo" } }
// ]
newRoot
: The document that will replace the root.The merge()
method is used to merge the pipeline output into an existing collection.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.merge({
into: "archivedUsers",
whenMatched: "merge",
whenNotMatched: "insert"
}) // Merge output into the 'archivedUsers' collection
.build();
console.log(pipeline);
// Output:
// [
// { $merge: { into: "archivedUsers", whenMatched: "merge", whenNotMatched: "insert" } }
// ]
mergeSpec
: The merge specification.The redact()
method is used to restrict the content of documents based on some criteria.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.redact({
$cond: {
if: { $eq: ['$role', 'admin'] },
then: "$$DESCEND",
else: "$$PRUNE"
}
}) // Restrict access to admin documents
.build();
console.log(pipeline);
// Output:
// [
// { $redact: { $cond: { if: { $eq: ['$role', 'admin'] }, then: "$$DESCEND", else: "$$PRUNE" } } }
// ]
redactExpr
: The redact expression object.The sample()
method is used to randomly select a specified number of documents from the collection.
// Example
const pipeline = MongoSense()
.collection('users') // Select the 'users' collection
.sample(10) // Randomly select 10 documents
.build();
console.log(pipeline);
// Output:
// [
// { $sample: { size: 10 } }
// ]
size
: The number of documents to randomly select.MongoSense allows for dynamic and flexible query building with conditional stages. You can add stages like $match
, $sort
, $limit
, $skip
, $lookup
, $group
, $addFields
, $bucket
, $bucketAuto
, $count
, $facet
, $project
, $unwind
, $out
, $replaceRoot
, $merge
, $redact
, and $sample
only if the input is provided. If null
or undefined
is passed, the stage is skipped.
// Example:
const pipeline = MongoSense()
.collection('users')
.match({ isActive: true }) // Add $match stage if criteria is provided
.sort(null) // Skip $sort stage if no sorting is needed
.limit(10) // Add $limit stage if provided
.addFields(null) // Skip $addFields stage if no fields are provided
.sample(10) // Add $sample stage if size is provided
.build();
console.log(pipeline);
// Output:
// [
// { $match: { isActive: true } },
// { $limit: 10 },
// { $sample: { size: 10 } }
// ]
null
or undefined
to any method, the corresponding stage will be skipped.$match
, $sort
, $limit
, $skip
, $lookup
, $group
, $addFields
, $bucket
, $bucketAuto
, $count
, $facet
, $project
, $unwind
, $out
, $replaceRoot
, $merge
, $redact
, and $sample
.The IntelliOptimizer
is an optional performance-first engine for query optimization, index recommendations, and index creation in MongoDB. This can be enabled by passing the IntelliOptimizer
instance to the MongoSenseQueryBuilder
. It helps reorder query stages for performance and suggests or automatically creates indexes for optimized querying.
To use the Intelli optimizer, you need to initialize the IntelliOptimizer
class with a MongoDB connection and pass it to the MongoSenseQueryBuilder
factory.
import { MongoClient } from 'mongodb';
import { MongoSense } from './queryBuilder';
import IntelliOptimizer from './intelli';
async function main() {
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
// Initialize IntelliOptimizer with the MongoDB client
const intelli = new IntelliOptimizer(client);
const builder = MongoSense(true, intelli)
.collection('users')
.match({ isActive: true }) // $match stage
.sort({ createdAt: -1 }) // $sort stage
.limit(10);
await builder.optimize(); // Perform optimizations (reordering and index recommendations)
const pipeline = builder.build();
console.log(pipeline);
// Automatically create indexes if necessary
await builder.createIndexes();
await client.close();
}
main();
Index Recommendation
The Intelli engine can analyze query patterns (such as fields used in $match
and $sort
stages) and recommend indexes for those fields if they are not already indexed.
const recommendations = await optimizer.analyzeAndRecommendIndexes('users', ['isActive', 'createdAt']);
console.log('Recommended indexes:', recommendations);
Automatic Index Creation
After recommendations are made, Intelli can automatically create indexes for those fields to optimize MongoDB queries.
const createdIndexes = await optimizer.createIndexes('users', ['isActive', 'createdAt']);
console.log('Created indexes:', createdIndexes);
Pipeline Optimization
Intelli can reorder the pipeline stages, ensuring that $match
and $sort
stages appear earlier in the pipeline for better performance.
await builder.optimize(); // Automatically reorders stages for performance
Debug Mode
When debugMode
is enabled, Intelli logs its internal operations (such as pipeline optimization and index recommendations) for inspection.
const builder = MongoSense(true, intelli); // Enable debug mode
We welcome contributions! If you find a bug or have a feature request, please open an issue. Pull requests are also welcome.
To contribute:
git checkout -b feature/your-feature
)git commit -m 'Add new feature'
)git push origin feature/your-feature
)This repository is licensed under the MIT License. See the LICENSE file for more details.
FAQs
MongoSense is a flexible and easy-to-use MongoDB aggregation pipeline builder with IntelliOptimizer for performance-first query optimization.
We found that mongosense demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.