MongoDB Interview Questions with Answers
Most Asked MongoDB Interview Questions for Database Engineers and Developers
Introduction
MongoDB is a leading NoSQL document database that provides high performance, scalability, and flexibility for modern applications. This page compiles the most frequently asked MongoDB interview questions – from basic CRUD operations and data types to advanced topics like aggregation, indexing, sharding, replication, change streams, transactions, and performance optimisation – essential for backend developers, database administrators, and data engineers.
Why MongoDB?
- Document‑oriented – stores data as JSON‑like documents (BSON)
- Schema‑flexible – adapts to changing data models easily
- Horizontally scalable – sharding for large datasets
- High performance – optimized for read/write operations
- Rich query language – powerful aggregation and geospatial queries
- Enterprise‑ready – ACID transactions, security, and monitoring
Most Asked MongoDB Interview Questions
MongoDB is a NoSQL document database that stores data in flexible, JSON-like documents. It is designed for scalability, performance, and ease of development.
- Document-oriented: Stores data as JSON-like documents
- Schema-less: No predefined schema required
- Scalable: Horizontal scaling with sharding
- High performance: Indexing and query optimization
- Rich queries: Powerful query language and aggregation
// Hello World in MongoDB (using mongosh)
print("Hello, World!");
// Or using the mongo shell
db.runCommand({ ping: 1 });In the mongo shell (mongosh), variables are declared using var, let, or const like JavaScript.
- var: Global variable (function-scoped)
- let: Block-scoped variable
- const: Read-only constant
- Dynamic typing: Variables can hold any type
- Shell variables:
print()to display
// Variables in MongoDB (mongosh)
var mutableVar = "Hello"; // Mutable variable
let immutableVar = "World"; // Block-scoped variable
const constantVar = "Constant"; // Read-only variable
// Type inference
var inferred = 42;
// Display
print(mutableVar);
print(immutableVar);
print(inferred);
// Using shell
var name = "Alice";
print("Hello " + name);MongoDB supports various BSON data types including strings, numbers, booleans, dates, arrays, objects, and ObjectId.
- String: UTF-8 string
- Number: Double, Int32, Int64
- Boolean: true/false
- Date: ISODate
- Array: List of values
- Object: Embedded document
- ObjectId: 12-byte unique identifier
- Null: Represents null value
// Data Types in MongoDB
// String
var str = "Hello MongoDB";
// Number (Double)
var doubleNum = 3.14;
// Number (Int32)
var intNum = NumberInt(10);
// Number (Long)
var longNum = NumberLong(100);
// Boolean
var isActive = true;
var isInactive = false;
// Date
var date = new Date();
// Null
var nullValue = null;
// Array
var arr = [1, 2, 3, 4, 5];
// Object/Embedded Document
var person = {
name: "Alice",
age: 25,
city: "NYC"
};
// ObjectId
var id = ObjectId();
// Binary Data
var binaryData = BinData(0, "base64encoded");
// Regular Expression
var regex = /pattern/;
// Type checking
typeof intNum; // "number"Functions in MongoDB are defined using JavaScript syntax. They can be used in the shell, in $where queries, or as stored functions.
- Basic:
function name(params) - Default parameters:
function greet(name = "Guest") - Arrow functions:
(x) => x * 2 - Stored functions:
db.system.js.insert() - $function: Aggregation operator (4.4+)
// Functions in MongoDB (mongosh)
// Basic function
function add(a, b) {
return a + b;
}
// Function with default parameters
function greet(name = "Guest") {
return "Hello, " + name + "!";
}
// Function with multiple return values (using object)
function divide(a, b) {
return {
quotient: Math.floor(a / b),
remainder: a % b
};
}
// Higher-order function
function operate(a, b, operation) {
return operation(a, b);
}
// Lambda expression (arrow function)
var multiply = (a, b) => a * b;
// Anonymous function
var square = function(x) { return x * x; };
// Usage
print(add(5, 3));
print(greet("Alice"));
var result = divide(10, 3);
print(result.quotient);
print(result.remainder);
print(operate(6, 7, multiply));Arrays in MongoDB can store multiple values of any type, including nested documents and arrays.
- Creation:
[1, 2, 3] - Access:
array[0](0-indexed) - Modification:
array[2] = 10 - Operations:
push,pop,map,filter - Query operators:
$in,$all,$elemMatch
// Arrays in MongoDB
// Array creation
var numbers = [1, 2, 3, 4, 5];
var strings = ["Apple", "Banana", "Orange"];
var mixed = [1, "Hello", 3.14];
// Access and modify
numbers[2]; // Access element (0-indexed)
numbers[2] = 10; // Modify element
// Array operations
numbers.length;
numbers.push(6); // Add element
numbers.pop(); // Remove last element
// Iteration
for (var num of numbers) {
print(num);
}
// Array methods
var doubled = numbers.map(x => x * 2);
var filtered = numbers.filter(x => x > 2);
var sum = numbers.reduce((a, b) => a + b, 0);
// Display
print(doubled);
print(filtered);
print(sum);Collections are groups of documents, similar to tables in relational databases. They are created implicitly when inserting documents.
- Creation:
db.createCollection("name") - Insert:
db.collection.insertOne() - Find:
db.collection.find() - Update:
db.collection.updateOne() - Delete:
db.collection.deleteOne() - Capped collections: Fixed-size collections
// Collections in MongoDB
// Collections are created implicitly when inserting data
// Insert documents
db.users.insertOne({
name: "Alice",
age: 25,
city: "NYC"
});
db.users.insertMany([
{ name: "Bob", age: 30, city: "LA" },
{ name: "Charlie", age: 35, city: "Chicago" }
]);
// Find documents
db.users.find(); // All documents
db.users.findOne(); // First document
// Query with filter
db.users.find({ age: { $gt: 25 } });
// Update documents
db.users.updateOne(
{ name: "Alice" },
{ $set: { age: 26 } }
);
// Delete documents
db.users.deleteOne({ name: "Bob" });
db.users.deleteMany({ age: { $gt: 30 } });
// Count documents
db.users.countDocuments({ age: { $gt: 25 } });
// Display all
db.users.find().pretty();Documents are the basic units of data in MongoDB. They are JSON-like objects with key-value pairs.
- Structure:
{ key: value } - Nested documents:
{ address: { city: "NYC" } } - Arrays:
{ hobbies: ["reading", "gaming"] } - BSON types: Extended JSON types
- Field names: Cannot contain '.' or start with '$'
// Documents (Data Classes) in MongoDB
// MongoDB documents are JSON-like objects
// Basic document
var person = {
name: "Alice",
age: 25,
city: "Unknown"
};
// Nested document
var person2 = {
name: "Bob",
age: 30,
address: {
street: "123 Main St",
city: "LA",
zip: "90001"
}
};
// Array of documents
var person3 = {
name: "Charlie",
age: 35,
hobbies: ["reading", "gaming", "hiking"]
};
// Insert document
db.people.insertOne(person);
db.people.insertOne(person2);
db.people.insertOne(person3);
// Query nested fields
db.people.find({ "address.city": "LA" });
// Query array
db.people.find({ hobbies: "gaming" });Schema validation allows enforcing document structure rules using JSON Schema. It's optional but recommended for data integrity.
- Validation:
validator: { $jsonSchema: {...} } - Required fields:
required: ["name", "email"] - Types:
bsonType: "string" - Patterns:
pattern: "^.+@.+$" - Enums:
enum: ["active", "inactive"]
// Schema Validation in MongoDB
// MongoDB is schema-less, but validation can be added
// Create collection with validation
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: {
bsonType: "string",
description: "Name is required"
},
email: {
bsonType: "string",
pattern: "^.+@.+$",
description: "Email must be valid"
},
age: {
bsonType: "int",
minimum: 0,
maximum: 150
},
status: {
enum: ["active", "inactive", "pending"],
description: "Status must be one of the enum values"
}
}
}
}
});
// Insert with validation
db.users.insertOne({
name: "Alice",
email: "alice@example.com",
age: 25,
status: "active"
});MongoDB uses null and undefined to represent missing values. Various operators help handle null values safely.
- Null:
{ field: null } - Existence check:
$exists - Null check:
{ field: { $type: 10 } } - $ifNull: Default value in aggregation
- $cond: Conditional handling
// Null Safety in MongoDB
// MongoDB uses null and undefined
// Null values
db.users.insertOne({
name: "Alice",
email: null, // Explicit null
age: undefined // Undefined field
});
// Query for null
db.users.find({ email: null });
// Check for existence
db.users.find({ age: { $exists: true } });
// Check for null or missing
db.users.find({
$or: [
{ email: null },
{ email: { $exists: false } }
]
});
// Using $type to check
db.users.find({ email: { $type: 10 } }); // 10 = null type
// Default values using $ifNull (aggregation)
db.users.aggregate([
{
$project: {
name: 1,
email: {
$ifNull: ["$email", "No email provided"]
}
}
}
]);Query operators provide powerful filtering capabilities. They include comparison, logical, element, and evaluation operators.
- Comparison:
$eq,$gt,$lt,$in - Logical:
$and,$or,$not - Element:
$exists,$type - Evaluation:
$regex,$expr - Array:
$all,$elemMatch,$size
// Control Flow in MongoDB
// MongoDB queries use operators for control flow
// Comparison operators
db.users.find({ age: { $eq: 25 } }); // Equal to
db.users.find({ age: { $gt: 25 } }); // Greater than
db.users.find({ age: { $gte: 25 } }); // Greater than or equal
db.users.find({ age: { $lt: 25 } }); // Less than
db.users.find({ age: { $lte: 25 } }); // Less than or equal
db.users.find({ age: { $ne: 25 } }); // Not equal
// Logical operators
db.users.find({
$and: [
{ age: { $gte: 20 } },
{ age: { $lte: 30 } }
]
});
db.users.find({
$or: [
{ city: "NYC" },
{ city: "LA" }
]
});
db.users.find({
$nor: [
{ status: "inactive" }
]
});
db.users.find({
$not: { age: { $lt: 18 } }
});
// Conditional expression (aggregation)
db.users.aggregate([
{
$project: {
name: 1,
status: {
$cond: {
if: { $gte: ["$age", 18] },
then: "Adult",
else: "Minor"
}
}
}
}
]);References are used for relationships between documents. They can be manual references (using ObjectId) or DBRef.
- Manual reference:
{ userId: ObjectId("...") } - DBRef:
{ $ref: "collection", $id: ObjectId("...") } - $lookup: Join collections in aggregation
- Referencing: Store references, not embedded data
- Resolution: Use
$lookupto resolve references
// Classes and Inheritance in MongoDB
// MongoDB doesn't have classes, but uses inheritance patterns
// Single Collection Inheritance
db.animals.insertMany([
{
_type: "Animal",
name: "Generic",
sound: "Animal sound"
},
{
_type: "Dog",
name: "Rex",
breed: "German Shepherd",
sound: "Woof!"
}
]);
// Query by type
db.animals.find({ _type: "Dog" });
// Document references (Manual Reference)
var dogId = ObjectId();
db.dogs.insertOne({
_id: dogId,
name: "Rex",
breed: "German Shepherd"
});
db.owners.insertOne({
name: "Alice",
dogId: dogId
});
// Query with reference
db.owners.aggregate([
{
$lookup: {
from: "dogs",
localField: "dogId",
foreignField: "_id",
as: "dog"
}
}
]);Fields are the key-value pairs in MongoDB documents. They can store any BSON data type and can be nested.
- Field names: Strings, cannot contain '.'
- Field values: Any BSON type
- Nested fields:
{"address.city": "NYC"} - Field projection: Include/exclude fields
- Field validation: Using schema validation
// Properties/Fields in MongoDB
// Fields are defined in documents
// Basic fields
db.users.insertOne({
name: "Alice",
age: 25,
email: "alice@example.com",
isActive: true,
createdAt: new Date()
});
// Computed fields (using aggregation)
db.users.aggregate([
{
$addFields: {
fullName: {
$concat: ["$firstName", " ", "$lastName"]
},
ageInDays: {
$multiply: ["$age", 365]
}
}
}
]);
// Field validation using schema
db.createCollection("validatedUsers", {
validator: {
$jsonSchema: {
properties: {
name: { bsonType: "string" },
age: { bsonType: "int", minimum: 0 }
}
}
}
});
// Field projection
db.users.find({}, { name: 1, age: 1, _id: 0 });
// Field existence
db.users.find({ email: { $exists: true } });Stored functions are JavaScript functions stored in the system.js collection. They can be called using db.eval().
- Storage:
db.system.js.insertOne() - Execution:
db.eval("functionName()") - Use cases: Complex calculations, data transformation
- Limitations: Performance overhead, security concerns
- Alternatives: Use aggregation or application code
// Static Methods in MongoDB
// MongoDB uses stored JavaScript functions
// Stored function (server-side)
db.system.js.insertOne({
_id: "calculateAge",
value: function(birthYear) {
return new Date().getFullYear() - birthYear;
}
});
// Stored function with multiple operations
db.system.js.insertOne({
_id: "processUser",
value: function(userData) {
var user = {
name: userData.name,
age: userData.birthYear ?
new Date().getFullYear() - userData.birthYear :
null,
createdAt: new Date(),
status: "active"
};
return user;
}
});
// Call stored function
var age = db.eval("calculateAge(1990)");
// Stored procedure-like function
db.system.js.insertOne({
_id: "createUser",
value: function(name, email) {
return db.users.insertOne({
name: name,
email: email,
createdAt: new Date()
});
}
});Exceptions in MongoDB can be handled using try-catch blocks in the shell or application code.
- try-catch:
try catch (error) - Validation errors: Schema validation failures
- Duplicate key errors: Unique index violations
- Network errors: Connection issues
- Bulk operations: Handle partial failures
// Exception Handling in MongoDB
// Using try-catch in mongosh
// Try-catch block
try {
var result = db.users.insertOne({
name: "Alice",
age: "invalid" // Wrong type
});
print(result);
} catch (error) {
print("Error: " + error.message);
}
// Custom error handling
function safeInsert(collection, document) {
try {
var result = collection.insertOne(document);
return { success: true, result: result };
} catch (error) {
return {
success: false,
error: error.message
};
}
}
// Using with validation
try {
db.validatedUsers.insertOne({
name: "Bob",
age: -5 // Will fail validation
});
} catch (error) {
print("Validation error: " + error.message);
}
// Bulk operation with error handling
var bulk = db.users.initializeUnorderedBulkOp();
bulk.insert({ name: "Alice" });
bulk.insert({ name: "Bob" });
try {
var result = bulk.execute();
print("Success: " + result.nInserted);
} catch (error) {
print("Bulk error: " + error.message);
}Lambda expressions (arrow functions) are used in the mongo shell and in $function aggregation operator.
- Syntax:
(x) => x * 2 - Array methods:
map,filter,reduce - $function: Use JavaScript in aggregation
- MapReduce: Use functions for map and reduce
- Performance: Use aggregation instead when possible
// Lambda Expressions in MongoDB
// Using arrow functions in mongosh
// Basic lambda
var square = (x) => x * x;
// Lambda with multiple parameters
var add = (a, b) => a + b;
// Higher-order functions
function operate(x, y, operation) {
return operation(x, y);
}
// Array methods with lambdas
var numbers = [1, 2, 3, 4, 5];
var doubled = numbers.map(x => x * 2);
var filtered = numbers.filter(x => x > 2);
var sum = numbers.reduce((a, b) => a + b, 0);
// Aggregation with lambda-like operators
db.users.aggregate([
{
$project: {
name: 1,
isAdult: {
$cond: {
if: { $gte: ["$age", 18] },
then: true,
else: false
}
}
}
}
]);
// MapReduce with functions
db.users.mapReduce(
function() { emit(this.age, 1); },
function(key, values) { return Array.sum(values); },
{ out: "ageCount" }
);Scope functions like forEach, map, and reduce allow iterating and transforming data in the shell.
- forEach:
cursor.forEach(function(doc) ) - map:
cursor.map(function(doc) ) - Aggregation:
$project,$addFields - $function: Custom JavaScript in aggregation
- Apply:
Array.apply(null, { length: n })
// Scope Functions in MongoDB
// Using functions and blocks in mongosh
// let - execute block
function processUser(user) {
if (user) {
let name = user.name;
let age = user.age;
print("Name: " + name);
user.age = 26;
return user;
}
}
// Using with forEach
db.users.find().forEach(function(user) {
print("User: " + user.name);
});
// Using map
var names = db.users.find().map(function(user) {
return user.name;
});
// Using $project for transformation
db.users.aggregate([
{
$project: {
name: 1,
age: 1,
ageInDays: { $multiply: ["$age", 365] }
}
}
]);
// take-if equivalent
function takeIf(condition, value) {
return condition(value) ? value : null;
}
// Usage
var adult = takeIf(function(age) { return age >= 18; }, 25);MongoDB doesn't have extension functions directly, but you can create wrapper functions and use aggregation operators.
- Wrapper functions: Custom JavaScript functions
- Aggregation operators:
$regexMatch,$type - $function: Custom JavaScript in aggregation
- Stored functions:
system.js - Application code: Implement extensions in drivers
// Extension Functions in MongoDB
// MongoDB doesn't have extension functions directly
// Using wrapper functions and aggregation
// String extensions
function isEmail(str) {
return /^.+@.+$/.test(str);
}
function addPrefix(str, prefix) {
return prefix + str;
}
// Numeric extensions
function isEven(n) {
return n % 2 === 0;
}
function isOdd(n) {
return n % 2 !== 0;
}
// Array extensions
function secondOrNull(arr) {
return arr.length >= 2 ? arr[1] : null;
}
// Using with queries
db.users.find({
$where: "isEmail(this.email)"
});
// Aggregation with custom functions
db.users.aggregate([
{
$project: {
name: 1,
emailValid: {
$regexMatch: {
input: "$email",
regex: "^.+@.+$"
}
}
}
}
]);Field aliases in MongoDB are created using $project in aggregation. They allow renaming fields in output.
- $project:
newName: "$oldName" - Computed fields:
fullName: { $concat: [...] } - View creation: Virtual collections with aliases
- Renaming:
$addFieldswith$mergeObjects - Projection: Include/exclude original fields
// Type Aliases in MongoDB
// MongoDB doesn't have type aliases
// Using field aliases and projections
// Field aliases using $project
db.users.aggregate([
{
$project: {
userName: "$name",
userAge: "$age",
userEmail: "$email"
}
}
]);
// Alias for complex fields
db.users.aggregate([
{
$project: {
fullName: {
$concat: ["$firstName", " ", "$lastName"]
},
ageCategory: {
$cond: {
if: { $gte: ["$age", 18] },
then: "Adult",
else: "Minor"
}
}
}
}
]);
// View creation (virtual collection)
db.createView("activeUsers", "users", [
{ $match: { status: "active" } }
]);
// Using with find
db.activeUsers.find();
// Rename fields in output
db.users.find().forEach(function(user) {
var newUser = {
userName: user.name,
userAge: user.age
};
printjson(newUser);
});Inline functions can be used in $where queries, $function, or as stored functions in system.js.
- $where:
$where: "this.age > 18" - $function:
$function: { body: function() {...}, args: [...] } - Stored functions:
db.system.js.insert() - Performance: Use aggregation when possible
- Security: Avoid
$wherein production
// Inline Functions in MongoDB
// MongoDB doesn't have inline functions like Kotlin
// Using server-side JavaScript functions
// Stored function
db.system.js.insertOne({
_id: "measureTime",
value: function(fn) {
var start = new Date().getTime();
fn();
var end = new Date().getTime();
return end - start;
}
});
// Using stored function
var time = db.eval("measureTime(function() { sleep(1000); })");
print("Time: " + time + "ms");
// Function in query
db.users.find({
$where: function() {
return this.age >= 18 && this.age <= 65;
}
});
// Inline validation
db.users.find({
$expr: {
$and: [
{ $gte: ["$age", 18] },
{ $lte: ["$age", 65] }
]
}
});
// Type checking using $type
db.users.find({ age: { $type: "int" } });Higher-order functions in MongoDB are implemented through aggregation pipeline stages, array operators, and JavaScript functions.
- Aggregation stages:
$project,$group,$match - Array operators:
$map,$filter,$reduce - $facet: Multiple aggregations
- $lookup: Join collections
- Function composition: Chaining stages
// Higher-Order Functions in MongoDB
// Using functions in aggregation pipeline
// Function composition in aggregation
db.users.aggregate([
{
$match: { age: { $gte: 18 } }
},
{
$project: {
name: 1,
ageInDays: { $multiply: ["$age", 365] }
}
},
{
$sort: { age: -1 }
}
]);
// Custom aggregation functions
db.users.aggregate([
{
$facet: {
adults: [
{ $match: { age: { $gte: 18 } } },
{ $count: "count" }
],
minors: [
{ $match: { age: { $lt: 18 } } },
{ $count: "count" }
]
}
}
]);
// Function that returns a function (using JavaScript)
function getMultiplier(factor) {
return function(x) {
return x * factor;
};
}
var double = getMultiplier(2);
print(double(5));
// Using with array methods
var numbers = [1, 2, 3, 4, 5];
var processed = numbers
.filter(x => x > 2)
.map(x => x * 2)
.reduce((a, b) => a + b, 0);
print(processed);The aggregation pipeline is a framework for data processing and transformation. It consists of stages that process documents sequentially.
- Stages:
$match,$group,$project - Processing: Documents flow through stages
- Performance: Use indexes and early filtering
- Complex operations:
$lookup,$unwind - Output:
$out,$merge
// Aggregation Pipeline in MongoDB
// The aggregation pipeline is MongoDB's powerful data processing framework
// Basic pipeline
db.users.aggregate([
{ $match: { age: { $gte: 18 } } },
{ $group: { _id: "$city", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]);
// Multiple stages
db.orders.aggregate([
{
$match: {
status: "completed",
date: { $gte: ISODate("2023-01-01") }
}
},
{
$group: {
_id: "$customerId",
totalSpent: { $sum: "$amount" },
orderCount: { $sum: 1 }
}
},
{
$lookup: {
from: "customers",
localField: "_id",
foreignField: "_id",
as: "customer"
}
},
{
$unwind: "$customer"
},
{
$project: {
customerName: "$customer.name",
totalSpent: 1,
orderCount: 1
}
}
]);
// $facet for multiple aggregations
db.orders.aggregate([
{
$facet: {
totalRevenue: [
{ $group: { _id: null, total: { $sum: "$amount" } } }
],
byStatus: [
{ $group: { _id: "$status", count: { $sum: 1 } } }
],
byCustomer: [
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
]
}
}
]);Change streams provide real-time notifications of data changes. They are used for event-driven architectures and monitoring.
- Watch:
db.collection.watch() - Events: insert, update, delete, replace
- Resume tokens: Resume from interruption
- Filters: Match specific operations
- Full document:
fullDocument: "updateLookup"
// Change Streams in MongoDB
// Change streams allow real-time notification of database changes
// Watch a collection
var changeStream = db.users.watch();
// Watch with pipeline
var changeStream = db.users.watch([
{
$match: {
operationType: { $in: ["insert", "update"] }
}
}
]);
// Process changes
changeStream.on("change", function(change) {
print("Change detected!");
printjson(change);
});
// Watch with resume token
var resumeToken = null;
var changeStream = db.users.watch([], {
resumeAfter: resumeToken
});
// Watch entire database
var changeStream = db.watch();
// Watch with full document
var changeStream = db.users.watch([], {
fullDocument: "updateLookup"
});
// Stop watching
changeStream.close();
// Example: Real-time notification
db.users.watch([
{
$match: {
operationType: "insert"
}
}
]).on("change", function(change) {
print("New user added: " + change.fullDocument.name);
});Change streams can be resumed using resume tokens or timestamps. This ensures no data is missed during interruptions.
- Resume token:
resumeAfter - Start time:
startAtOperationTime - Token storage: Persist token for recovery
- Error handling: Resume on errors
- Multiple streams: Different operations
// Change Streams with Resume in MongoDB
// Change streams can resume from a point in time
// Get resume token
var changeStream = db.users.watch();
var resumeToken = null;
changeStream.on("change", function(change) {
resumeToken = change._id;
print("Change detected, token saved");
});
// Resume from token
var changeStream = db.users.watch([], {
resumeAfter: resumeToken
});
// Resume from specific time
var startTime = new Date("2023-01-01T00:00:00Z");
var changeStream = db.users.watch([], {
startAtOperationTime: Timestamp(startTime.getTime() / 1000, 0)
});
// Multiple change streams
var insertStream = db.users.watch([
{ $match: { operationType: "insert" } }
]);
var updateStream = db.users.watch([
{ $match: { operationType: "update" } }
]);
// Error handling
try {
var changeStream = db.users.watch();
changeStream.on("change", function(change) {
// Process change
});
} catch (error) {
print("Change stream error: " + error.message);
}MongoDB supports multi-document ACID transactions for replica sets and sharded clusters. They provide atomicity for multiple operations.
- Session:
db.getMongo().startSession() - Start:
session.startTransaction() - Commit:
session.commitTransaction() - Abort:
session.abortTransaction() - Retry: Handle transient errors
// Transactions in MongoDB
// MongoDB supports multi-document ACID transactions
// Start a session
var session = db.getMongo().startSession();
// Start transaction
session.startTransaction();
try {
var users = session.getDatabase("test").users;
var orders = session.getDatabase("test").orders;
// Operations
users.updateOne(
{ _id: "user123" },
{ $inc: { balance: -100 } }
);
orders.insertOne({
userId: "user123",
amount: 100,
status: "pending"
});
// Commit transaction
session.commitTransaction();
print("Transaction committed successfully");
} catch (error) {
// Abort on error
session.abortTransaction();
print("Transaction aborted: " + error.message);
} finally {
session.endSession();
}
// Transaction with retry
function runTransactionWithRetry() {
var session = db.getMongo().startSession();
session.startTransaction();
try {
// Operations
session.commitTransaction();
} catch (error) {
if (error.hasOwnProperty("errorLabels") &&
error.errorLabels.includes("TransientTransactionError")) {
// Retry transaction
runTransactionWithRetry();
} else {
session.abortTransaction();
throw error;
}
} finally {
session.endSession();
}
}Indexes improve query performance by reducing the number of documents scanned. They are essential for efficient queries.
- Single field:
db.collection.createIndex({ field: 1 }) - Compound:
{ field1: 1, field2: -1 } - Unique:
{ unique: true } - Text:
{ content: "text" } - TTL:
{ expireAfterSeconds: 3600 }
// Indexing in MongoDB
// Indexes improve query performance
// Create single field index
db.users.createIndex({ name: 1 });
// Create compound index
db.users.createIndex({ name: 1, age: -1 });
// Create unique index
db.users.createIndex({ email: 1 }, { unique: true });
// Create text index
db.articles.createIndex({ content: "text" });
// Create geospatial index
db.locations.createIndex({ location: "2dsphere" });
// Create partial index
db.users.createIndex(
{ age: 1 },
{ partialFilterExpression: { age: { $gte: 18 } } }
);
// Create TTL index
db.sessions.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 3600 }
);
// List indexes
db.users.getIndexes();
// Drop index
db.users.dropIndex("name_1");
// Explain query plan
db.users.find({ name: "Alice" }).explain("executionStats");
// Index usage
db.users.find({ name: "Alice", age: 25 }).hint({ name: 1, age: -1 });Sharding distributes data across multiple servers for horizontal scaling. It provides high availability and performance for large datasets.
- Shard key:
sh.shardCollection("db.collection", { key: 1 }) - Hashed sharding:
sh.shardCollection("db.collection", { key: "hashed" }) - Zones: Data distribution by region
- Chunks: Data partitions
- Balancer: Distributes chunks evenly
// Sharding in MongoDB
// Sharding distributes data across multiple servers
// Enable sharding for database
sh.enableSharding("myDatabase");
// Shard a collection
sh.shardCollection("myDatabase.users", { _id: "hashed" });
// Shard by range
sh.shardCollection("myDatabase.orders", { customerId: 1 });
// Compound shard key
sh.shardCollection("myDatabase.orders", {
customerId: 1,
orderDate: -1
});
// Hashed shard key
sh.shardCollection("myDatabase.products", { productId: "hashed" });
// Add shard
sh.addShard("shard1.example.com:27017");
sh.addShard("shard2.example.com:27017");
// Shard status
sh.status();
// Check shard distribution
db.users.getShardDistribution();
// Zone sharding
sh.addShardToZone("shard1", "US");
sh.addShardToZone("shard2", "EU");
// Tag range
sh.updateZoneKeyRange(
"myDatabase.users",
{ country: "US" },
{ country: "US" },
"US"
);Replication provides high availability and data redundancy through replica sets. It maintains multiple copies of data.
- Replica set:
rs.initiate() - Primary: Accepts writes
- Secondaries: Replicate data
- Arbiter: Voting only
- Read preference:
readPref("secondary")
// Replication in MongoDB
// Replication provides high availability and data redundancy
// Replica set configuration
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "localhost:27017", priority: 2 },
{ _id: 1, host: "localhost:27018", priority: 1 },
{ _id: 2, host: "localhost:27019", priority: 0, arbiterOnly: true }
]
});
// Add member to replica set
rs.add("localhost:27020");
// Remove member
rs.remove("localhost:27020");
// Reconfigure replica set
rs.reconfig({
_id: "rs0",
members: [
{ _id: 0, host: "localhost:27017", priority: 2 },
{ _id: 1, host: "localhost:27018", priority: 1 },
{ _id: 2, host: "localhost:27019", priority: 0 }
]
});
// Check status
rs.status();
// Check isMaster
db.isMaster();
// Force primary election
rs.stepDown();
// Set read preference
db.getMongo().setReadPref("secondaryPreferred");
// Read from secondary
db.users.find().readPref("secondary");
// Write concern
db.users.insertOne(
{ name: "Alice" },
{ writeConcern: { w: "majority" } }
);Data modeling patterns help design efficient data structures for specific use cases and query patterns.
- Embedded documents: One-to-one, one-to-many
- References: Many-to-many
- Bucket pattern: Time-series data
- Extended reference: Denormalized data
- Subset pattern: Frequently accessed fields
// MongoDB Data Modeling
// Data modeling patterns for MongoDB
// Embedded documents (one-to-one)
db.users.insertOne({
_id: "user123",
name: "Alice",
address: {
street: "123 Main St",
city: "NYC",
zip: "10001"
}
});
// Array of embedded documents (one-to-many)
db.users.insertOne({
_id: "user123",
name: "Alice",
orders: [
{ orderId: "ord1", amount: 100 },
{ orderId: "ord2", amount: 200 }
]
});
// Reference pattern (many-to-many)
db.orders.insertOne({
_id: "ord1",
customerId: "user123",
amount: 100
});
// Bucket pattern (time-series)
db.sensorData.insertOne({
sensorId: "sensor1",
readings: [
{ timestamp: ISODate("2023-01-01T00:00:00Z"), value: 25 },
{ timestamp: ISODate("2023-01-01T00:01:00Z"), value: 26 }
]
});
// Extended reference pattern
db.orders.insertOne({
_id: "ord1",
customer: {
id: "user123",
name: "Alice",
email: "alice@example.com"
},
amount: 100
});
// Subset pattern
db.products.insertOne({
_id: "prod1",
name: "Product 1",
price: 99.99,
// Detailed info stored separately
detailsId: "detail1"
});Query operators provide powerful filtering, comparison, and evaluation capabilities for queries.
- Comparison:
$eq,$gt,$lt,$in - Logical:
$and,$or,$not - Element:
$exists,$type - Evaluation:
$regex,$expr - Array:
$all,$elemMatch,$size
// MongoDB Query Operators
// Comparison operators
// $eq - Equal to
db.users.find({ age: { $eq: 25 } });
// $gt - Greater than
db.users.find({ age: { $gt: 25 } });
// $gte - Greater than or equal
db.users.find({ age: { $gte: 25 } });
// $lt - Less than
db.users.find({ age: { $lt: 25 } });
// $lte - Less than or equal
db.users.find({ age: { $lte: 25 } });
// $ne - Not equal
db.users.find({ age: { $ne: 25 } });
// $in - In array
db.users.find({ city: { $in: ["NYC", "LA", "Chicago"] } });
// $nin - Not in array
db.users.find({ city: { $nin: ["NYC", "LA"] } });
// Logical operators
// $and
db.users.find({
$and: [
{ age: { $gte: 18 } },
{ age: { $lte: 65 } }
]
});
// $or
db.users.find({
$or: [
{ city: "NYC" },
{ status: "active" }
]
});
// $nor
db.users.find({
$nor: [
{ status: "inactive" },
{ age: { $lt: 18 } }
]
});
// $not
db.users.find({
age: { $not: { $lt: 18 } }
});
// Element operators
// $exists
db.users.find({ email: { $exists: true } });
// $type
db.users.find({ age: { $type: "int" } });
// Evaluation operators
// $regex
db.users.find({ name: { $regex: /^A/ } });
// $expr
db.users.find({
$expr: {
$gt: ["$age", "$minAge"]
}
});
// $jsonSchema
db.users.find({
$jsonSchema: {
required: ["name", "age"]
}
});
// Array operators
// $all
db.users.find({ hobbies: { $all: ["reading", "gaming"] } });
// $elemMatch
db.users.find({
orders: {
$elemMatch: {
amount: { $gt: 100 },
status: "completed"
}
}
});
// $size
db.users.find({ hobbies: { $size: 3 } });Aggregation operators provide powerful data transformation capabilities in the aggregation pipeline.
- Grouping:
$group,$sum,$avg - Projection:
$project,$addFields - Array:
$unwind,$push,$addToSet - Joins:
$lookup - Conditional:
$cond,$switch
// MongoDB Aggregation Operators
// Grouping and accumulation
// $group - Group documents
db.orders.aggregate([
{
$group: {
_id: "$customerId",
totalAmount: { $sum: "$amount" },
averageAmount: { $avg: "$amount" },
minAmount: { $min: "$amount" },
maxAmount: { $max: "$amount" },
count: { $sum: 1 }
}
}
]);
// $project - Shape documents
db.users.aggregate([
{
$project: {
name: 1,
age: 1,
ageInDays: { $multiply: ["$age", 365] },
isAdult: { $gte: ["$age", 18] }
}
}
]);
// $unwind - Deconstruct array
db.orders.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: "$items.productId",
totalSold: { $sum: "$items.quantity" }
}
}
]);
// $lookup - Join collections
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
},
{ $unwind: "$customer" }
]);
// $addFields - Add computed fields
db.users.aggregate([
{
$addFields: {
fullName: {
$concat: ["$firstName", " ", "$lastName"]
},
ageCategory: {
$switch: {
branches: [
{ case: { $lt: ["$age", 18] }, then: "Minor" },
{ case: { $lt: ["$age", 65] }, then: "Adult" }
],
default: "Senior"
}
}
}
}
]);
// $sort - Sort documents
db.users.aggregate([
{ $sort: { age: -1, name: 1 } }
]);
// $limit - Limit results
db.users.aggregate([
{ $sort: { age: -1 } },
{ $limit: 10 }
]);
// $skip - Skip documents
db.users.aggregate([
{ $sort: { age: -1 } },
{ $skip: 10 },
{ $limit: 10 }
]);
// $sample - Random documents
db.users.aggregate([
{ $sample: { size: 5 } }
]);
// $facet - Multiple aggregations
db.orders.aggregate([
{
$facet: {
totalRevenue: [
{ $group: { _id: null, total: { $sum: "$amount" } } }
],
byStatus: [
{ $group: { _id: "$status", count: { $sum: 1 } } }
]
}
}
]);Views are read-only virtual collections that present data from other collections. They are created using aggregation pipelines.
- Create:
db.createView("name", "source", [pipeline]) - Read-only: Cannot write to views
- Pipeline:
$match,$project,$group - Materialized views: Using
$merge - Drop:
db.view.drop()
// MongoDB Views
// Views are read-only virtual collections
// Create a view
db.createView("activeUsers", "users", [
{ $match: { status: "active" } }
]);
// View with computed fields
db.createView("userStats", "users", [
{
$project: {
name: 1,
age: 1,
ageCategory: {
$switch: {
branches: [
{ case: { $lt: ["$age", 18] }, then: "Minor" },
{ case: { $lt: ["$age", 65] }, then: "Adult" }
],
default: "Senior"
}
}
}
}
]);
// View with aggregation
db.createView("orderSummary", "orders", [
{
$group: {
_id: "$customerId",
totalAmount: { $sum: "$amount" },
orderCount: { $sum: 1 }
}
},
{
$lookup: {
from: "customers",
localField: "_id",
foreignField: "_id",
as: "customer"
}
},
{ $unwind: "$customer" }
]);
// Query a view
db.activeUsers.find({ age: { $gt: 18 } });
// On-demand materialized views
db.orders.aggregate([
{
$merge: {
into: "materializedOrders",
on: "_id",
whenMatched: "replace",
whenNotMatched: "insert"
}
}
]);
// Drop a view
db.activeUsers.drop();MapReduce is a data processing framework that maps documents, reduces values, and outputs results. It's superseded by aggregation.
- Map: Emit key-value pairs
- Reduce: Aggregate values by key
- Finalize: Post-processing
- Output: Inline or collection
- Alternatives: Use aggregation pipeline
// MongoDB MapReduce
// MapReduce for data processing
// Basic MapReduce
db.orders.mapReduce(
function() {
emit(this.customerId, this.amount);
},
function(key, values) {
return Array.sum(values);
},
{
query: { status: "completed" },
out: "customerTotal"
}
);
// MapReduce with complex emit
db.orders.mapReduce(
function() {
emit(this.customerId, {
total: this.amount,
count: 1
});
},
function(key, values) {
var result = { total: 0, count: 0 };
for (var i = 0; i < values.length; i++) {
result.total += values[i].total;
result.count += values[i].count;
}
return result;
},
{
out: { inline: 1 }
}
);
// MapReduce with finalize
db.orders.mapReduce(
function() {
emit(this.customerId, this.amount);
},
function(key, values) {
return Array.sum(values);
},
{
out: "customerStats",
finalize: function(key, value) {
return {
customerId: key,
totalAmount: value,
formatted: "$" + value.toFixed(2)
};
}
}
);
// MapReduce with scope
var scopeVars = {
minAmount: 100
};
db.orders.mapReduce(
function() {
if (this.amount > minAmount) {
emit(this.customerId, this.amount);
}
},
function(key, values) {
return Array.sum(values);
},
{
out: "highValueCustomers",
scope: scopeVars
}
);Text search provides full-text search capabilities on string fields. It requires a text index and supports language-specific features.
- Text index:
{ content: "text" } - $text:
{ $text: { $search: "query" } } - Weights: Field importance
- Language:
$language - Score:
{ score: { $meta: "textScore" } }
// MongoDB Text Search
// Full-text search capabilities
// Create text index
db.articles.createIndex(
{ title: "text", content: "text" },
{ weights: { title: 10, content: 5 } }
);
// Basic text search
db.articles.find({
$text: {
$search: "MongoDB database"
}
});
// Text search with projection
db.articles.find(
{ $text: { $search: "MongoDB" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } });
// Text search with phrase
db.articles.find({
$text: {
$search: ""MongoDB tutorial""
}
});
// Text search with language
db.articles.find({
$text: {
$search: "database",
$language: "en"
}
});
// Text search with case sensitivity
db.articles.find({
$text: {
$search: "MongoDB",
$caseSensitive: true
}
});
// Text search with diacritic sensitivity
db.articles.find({
$text: {
$search: "café",
$diacriticSensitive: true
}
});
// Compound text index
db.articles.createIndex(
{ title: "text", content: "text", category: 1 },
{ weights: { title: 10, content: 5 } }
);Geospatial queries allow querying location-based data using 2dsphere and 2d indexes.
- 2dsphere index:
{ location: "2dsphere" } - $near:
{ $near: { $geometry: {...}, $maxDistance: 1000 } } - $geoWithin: Within polygon
- $geoIntersects: Intersects geometry
- $geoNear: Aggregation stage
// MongoDB Geospatial Queries
// Geospatial indexing and queries
// Create 2dsphere index
db.locations.createIndex({ location: "2dsphere" });
// Create 2d index
db.locations.createIndex({ location: "2d" });
// $near - Find nearby locations
db.locations.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [-73.9667, 40.78]
},
$maxDistance: 1000
}
}
});
// $geoWithin - Within polygon
db.locations.find({
location: {
$geoWithin: {
$geometry: {
type: "Polygon",
coordinates: [[
[-74.0, 40.7],
[-74.0, 40.8],
[-73.9, 40.8],
[-73.9, 40.7],
[-74.0, 40.7]
]]
}
}
}
});
// $geoIntersects - Intersects geometry
db.locations.find({
location: {
$geoIntersects: {
$geometry: {
type: "LineString",
coordinates: [
[-74.0, 40.7],
[-73.9, 40.8]
]
}
}
}
});
// $geoWithin with center
db.locations.find({
location: {
$geoWithin: {
$centerSphere: [
[-73.9667, 40.78],
0.01 // Radius in radians
]
}
}
});
// Geospatial aggregation
db.locations.aggregate([
{
$geoNear: {
near: {
type: "Point",
coordinates: [-73.9667, 40.78]
},
distanceField: "distance",
maxDistance: 1000,
spherical: true
}
}
]);GridFS is a specification for storing and retrieving large files (larger than 16MB) in MongoDB.
- Files:
fs.filescollection - Chunks:
fs.chunkscollection - Upload:
bucket.uploadFromStream() - Download:
bucket.openDownloadStream() - Metadata: Additional file information
// MongoDB GridFS
// GridFS for storing large files
// Store a file
var fileId = new ObjectId();
var bucket = new GridFSBucket(db, { bucketName: "files" });
bucket.uploadFromStream("file.txt", fileStream, {
_id: fileId,
metadata: {
owner: "user123",
uploaded: new Date()
}
});
// Download a file
var downloadStream = bucket.openDownloadStream(fileId);
downloadStream.pipe(fs.createWriteStream("downloaded.txt"));
// Find files
db.files.files.find({ "metadata.owner": "user123" });
// List files
bucket.find({ "metadata.owner": "user123" }).toArray();
// Delete a file
bucket.delete(fileId);
// Stream with progress
var uploadStream = bucket.openUploadStream("largeFile.txt", {
chunkSizeBytes: 1024 * 1024,
metadata: {
type: "document",
user: "user123"
}
});
uploadStream.on("finish", function() {
print("Upload completed");
});
uploadStream.on("error", function(error) {
print("Upload error: " + error);
});
// Rename a file
bucket.rename(fileId, "newName.txt");Capped collections are fixed-size collections that maintain insertion order and automatically overwrite old documents.
- Fixed size:
{ capped: true, size: 100000 } - Max documents:
{ max: 1000 } - Insertion order: Maintains order
- Tailable cursors:
cursor.tailable() - Use cases: Logging, caching
// MongoDB Capped Collections
// Capped collections for fixed-size data
// Create capped collection
db.createCollection("logs", {
capped: true,
size: 100000,
max: 1000
});
// Insert documents
db.logs.insertMany([
{ message: "Log entry 1", timestamp: new Date() },
{ message: "Log entry 2", timestamp: new Date() }
]);
// Tailable cursor
var cursor = db.logs.find().tailable();
cursor.forEach(function(doc) {
print(doc.message);
});
// Using with change streams
var changeStream = db.logs.watch();
changeStream.on("change", function(change) {
print("New log entry: " + change.fullDocument.message);
});
// Convert existing collection to capped
db.runCommand({
convertToCapped: "myCollection",
size: 100000
});
// Check if collection is capped
db.logs.isCapped();
// View collection stats
db.logs.stats();
// Capped collection limitations
// - Cannot be sharded
// - Cannot be updated if document grows
// - No indexes except _id
// - Order is insertion orderTTL (Time-To-Live) indexes automatically delete documents after a specified time. They are useful for expiring data.
- expireAfterSeconds:
{ expireAfterSeconds: 3600 } - Date field:
{ createdAt: 1 } - Partial filters:
{ partialFilterExpression: { status: "active" } } - Cleanup job: Runs periodically
- Use cases: Session cleanup, data retention
// MongoDB TTL Indexes
// TTL indexes for automatic document expiration
// Create TTL index
db.sessions.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 3600 }
);
// TTL with specific expiry date
db.sessions.createIndex(
{ expireAt: 1 },
{ expireAfterSeconds: 0 }
);
// Documents with TTL
db.sessions.insertOne({
userId: "user123",
token: "abc123",
createdAt: new Date(),
expireAt: new Date(Date.now() + 3600000)
});
// TTL with partial filter
db.sessions.createIndex(
{ createdAt: 1 },
{
expireAfterSeconds: 3600,
partialFilterExpression: { status: "active" }
}
);
// TTL cleanup job
db.runCommand({
compact: "sessions"
});
// Check TTL index
db.sessions.getIndexes();
// Drop TTL index
db.sessions.dropIndex("createdAt_1");
// TTL for different time periods
db.orders.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 30 * 24 * 60 * 60 } // 30 days
);
db.tempData.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 60 } // 1 minute
);The aggregation framework provides powerful data processing capabilities through a pipeline of stages.
- $lookup: Join collections with pipelines
- $graphLookup: Recursive joins
- $unionWith: Combine collections
- $merge: Output to collection
- $bucket: Group by ranges
// MongoDB Aggregation Framework
// Advanced aggregation techniques
// $lookup with pipeline
db.orders.aggregate([
{
$lookup: {
from: "customers",
let: { customerId: "$customerId" },
pipeline: [
{
$match: {
$expr: {
$eq: ["$_id", "$$customerId"]
}
}
},
{
$project: {
_id: 0,
name: 1,
email: 1
}
}
],
as: "customer"
}
}
]);
// $graphLookup for recursive queries
db.employees.aggregate([
{
$graphLookup: {
from: "employees",
startWith: "$managerId",
connectFromField: "managerId",
connectToField: "_id",
as: "managers",
maxDepth: 5
}
}
]);
// $unionWith for combining collections
db.orders.aggregate([
{
$unionWith: {
coll: "archivedOrders"
}
}
]);
// $merge for output
db.orders.aggregate([
{
$match: { status: "completed" }
},
{
$merge: {
into: "completedOrders",
on: "_id",
whenMatched: "replace",
whenNotMatched: "insert"
}
}
]);
// $bucket for grouping
db.orders.aggregate([
{
$bucket: {
groupBy: "$amount",
boundaries: [0, 100, 500, 1000],
default: "Other",
output: {
count: { $sum: 1 },
total: { $sum: "$amount" }
}
}
}
]);
// $bucketAuto for automatic buckets
db.orders.aggregate([
{
$bucketAuto: {
groupBy: "$amount",
buckets: 5,
output: {
count: { $sum: 1 },
average: { $avg: "$amount" }
}
}
}
]);Performance optimization involves proper indexing, query optimization, and efficient data modeling.
- Indexes: Create appropriate indexes
- Explain: Analyze query execution
- Covered queries: Index-only queries
- Projection: Return only needed fields
- Bulk operations: Batch inserts/updates
// MongoDB Performance Optimization
// Query optimization techniques
// Use proper indexes
db.users.createIndex({ email: 1 });
db.users.createIndex({ age: 1, status: 1 });
// Explain query
db.users.find({ email: "alice@example.com" }).explain("executionStats");
// Covered query
db.users.find(
{ email: "alice@example.com" },
{ _id: 0, email: 1, name: 1 }
);
// Query projection
db.users.find({ age: { $gt: 18 } }, { name: 1, age: 1 });
// Use $in with indexes
db.users.find({ city: { $in: ["NYC", "LA"] } });
// Avoid $where when possible
// Bad: db.users.find({ $where: "this.age > 18" })
// Good: db.users.find({ age: { $gt: 18 } })
// Use limit and skip for pagination
db.users.find().limit(20).skip(40);
// Use aggregation for complex queries
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } }
]);
// Bulk operations
var bulk = db.users.initializeUnorderedBulkOp();
bulk.insert({ name: "Alice" });
bulk.insert({ name: "Bob" });
bulk.execute();
// Use $hint to force index
db.users.find({ age: { $gt: 18 } }).hint({ age: 1 });
// Use $natural for collection scan
db.users.find().hint({ $natural: 1 });MongoDB provides authentication, authorization, encryption, and auditing for data security.
- Authentication: SCRAM, X.509
- Authorization: Role-based access control
- Encryption: TLS/SSL, encryption at rest
- Auditing: Activity logging
- Field-level encryption: Client-side encryption
// MongoDB Security
// Security features and best practices
// Enable authentication
use admin;
db.createUser({
user: "admin",
pwd: "password",
roles: ["root"]
});
// Create database user
use myDatabase;
db.createUser({
user: "appUser",
pwd: "appPassword",
roles: [
{ role: "readWrite", db: "myDatabase" }
]
});
// Role-based access control
db.createRole({
role: "customRole",
privileges: [
{
resource: { db: "myDatabase", collection: "users" },
actions: ["find", "insert", "update"]
}
],
roles: []
});
// Enable TLS/SSL
// mongod --tlsMode requireTLS --tlsCertificateKeyFile /path/to/cert.pem
// Enable encryption at rest
// mongod --enableEncryption --encryptionKeyFile /path/to/key
// Audit logging
db.setLogLevel(1, "accessControl");
// Connection string with authentication
// mongodb://username:password@localhost:27017/database
// Client-side field level encryption
// Requires enterprise edition
// Database access control
db.users.find().readConcern("majority");
// Write concern
db.users.insertOne(
{ name: "Alice" },
{ writeConcern: { w: "majority", wtimeout: 5000 } }
);
// IP Whitelisting
// mongod --bind_ip 127.0.0.1,192.168.1.100
// Enable authorization
// mongod --authFind maximum value using $max in aggregation or sorting with limit.
- Aggregation:
{ $group: { _id: null, max: { $max: "$age" } } } - Sort:
db.collection.find().sort({ age: -1 }).limit(1) - Array field: Use
$unwindfirst - $facet: Multiple aggregates
// MongoDB Backup and Restore
// Backup and restore methods
// mongodump - Backup
// mongodump --db myDatabase --out /backups/
// mongodump with gzip
// mongodump --db myDatabase --gzip --out /backups/
// mongodump specific collections
// mongodump --db myDatabase --collection users --out /backups/
// mongorestore - Restore
// mongorestore --db myDatabase /backups/myDatabase/
// mongorestore with gzip
// mongorestore --db myDatabase --gzip /backups/myDatabase/
// Backup with authentication
// mongodump --username admin --password password --authenticationDatabase admin
// Backup to archive
// mongodump --archive=/backups/dump.archive --db myDatabase
// Restore from archive
// mongorestore --archive=/backups/dump.archive
// Point-in-time recovery (with oplog)
// mongodump --oplog --out /backups/
// Restore with oplog
// mongorestore --oplogReplay /backups/
// Backup specific query
// mongodump --db myDatabase --collection users --query '{"status": "active"}'Remove duplicates using aggregation to find duplicates and then delete them.
- Find duplicates:
$groupwith$push - Keep first: Use
$first - Delete:
db.collection.deleteMany() - $out: Create unique collection
// MongoDB Monitoring
// Monitoring and performance tracking
// Server status
db.serverStatus();
// Database stats
db.stats();
// Collection stats
db.users.stats();
// Current operations
db.currentOp();
// Kill operation
db.killOp(opId);
// Query profiling
db.setProfilingLevel(2);
// Profiling level: 0-off, 1-slow, 2-all
db.getProfilingStatus();
// Slow query log
db.system.profile.find({ millis: { $gt: 100 } });
// Connection stats
db.serverStatus().connections;
// Memory stats
db.serverStatus().mem;
// Lock stats
db.serverStatus().locks;
// Replication lag
rs.printReplicationInfo();
// Oplog stats
db.getReplicationInfo();
// Index usage stats
db.users.aggregate([
{ $indexStats: {} }
]);
// Log rotation
db.adminCommand({ logRotate: 1 });
// Server status as JSON
printjson(db.serverStatus());Merge arrays using $concatArrays or $setUnion for unique values.
- $concatArrays:
{ $concatArrays: ["$arr1", "$arr2"] } - $setUnion:
{ $setUnion: ["$arr1", "$arr2"] } - $reduce: Custom merge logic
- $mergeObjects: Merge documents
// Find max in array (MongoDB)
// Using aggregation
db.users.aggregate([
{ $group: { _id: null, maxAge: { $max: "$age" } } }
]);
// Using find with sort
db.users.find().sort({ age: -1 }).limit(1);
// Find max in array field
db.orders.aggregate([
{ $unwind: "$items" },
{ $group: { _id: null, maxPrice: { $max: "$items.price" } } }
]);
// Using $max in $project
db.users.aggregate([
{
$project: {
name: 1,
age: 1,
maxAge: { $max: ["$age", "$parentAge"] }
}
}
]);
// Find document with max value
db.users.find({ age: { $eq: 25 } }).sort({ age: -1 }).limit(1);
// Using $facet for multiple aggregates
db.users.aggregate([
{
$facet: {
maxAge: [
{ $group: { _id: null, max: { $max: "$age" } } }
],
minAge: [
{ $group: { _id: null, min: { $min: "$age" } } }
]
}
}
]);Convert string to number using $toInt, $toDouble, or $toDecimal.
- $toInt:
{ $toInt: "$age" } - $toDouble:
{ $toDouble: "$amount" } - $convert: With error handling
- $cond: Handle invalid values
// Remove duplicates (MongoDB)
// Using aggregation to find duplicates
db.users.aggregate([
{
$group: {
_id: "$email",
count: { $sum: 1 },
ids: { $push: "$_id" }
}
},
{
$match: { count: { $gt: 1 } }
}
]);
// Remove duplicates keeping first
var duplicates = db.users.aggregate([
{
$group: {
_id: "$email",
ids: { $push: "$_id" }
}
},
{
$match: { "ids.1": { $exists: true } }
}
]);
duplicates.forEach(function(doc) {
var keepId = doc.ids[0];
var removeIds = doc.ids.slice(1);
db.users.deleteMany({ _id: { $in: removeIds } });
});
// Remove duplicates using $out
db.users.aggregate([
{
$group: {
_id: "$email",
doc: { $first: "$$ROOT" }
}
},
{
$replaceRoot: { newRoot: "$doc" }
},
{ $out: "uniqueUsers" }
]);
// Find duplicate emails
db.users.aggregate([
{
$group: {
_id: "$email",
count: { $sum: 1 }
}
},
{ $match: { count: { $gt: 1 } } }
]);Loop through arrays using $map, $filter, $reduce, or $unwind.
- $map: Transform each element
- $filter: Select elements
- $reduce: Aggregate elements
- $unwind: Deconstruct array
// Merge arrays (MongoDB)
// Using $concatArrays
db.users.aggregate([
{
$project: {
name: 1,
allHobbies: {
$concatArrays: ["$hobbies", "$interests"]
}
}
}
]);
// Merge arrays of objects
db.orders.aggregate([
{
$project: {
allItems: {
$concatArrays: ["$items", "$bonusItems"]
}
}
}
]);
// Merge with unique values
db.users.aggregate([
{
$project: {
name: 1,
allHobbies: {
$setUnion: ["$hobbies", "$interests"]
}
}
}
]);
// Merge arrays from multiple documents
db.users.aggregate([
{
$group: {
_id: null,
allNames: { $push: "$name" }
}
},
{
$project: {
allNames: {
$reduce: {
input: "$allNames",
initialValue: [],
in: { $concatArrays: ["$$value", ["$$this"]] }
}
}
}
}
]);
// Merge with $mergeObjects
db.users.aggregate([
{
$group: {
_id: "$userId",
data: { $mergeObjects: "$$ROOT" }
}
}
]);Delay execution using sleep(), setTimeout, or scheduling tasks.
- sleep():
sleep(1000) - setTimeout:
setTimeout(fn, delay) - setInterval:
setInterval(fn, interval) - Scheduled tasks: Store and poll
// Convert string to number (MongoDB)
// Using $toInt
db.users.aggregate([
{
$project: {
name: 1,
ageInt: { $toInt: "$age" }
}
}
]);
// Convert string to decimal
db.orders.aggregate([
{
$project: {
amountDecimal: { $toDecimal: "$amountString" }
}
}
]);
// Convert string to double
db.orders.aggregate([
{
$project: {
amountDouble: { $toDouble: "$amountString" }
}
}
]);
// Safe conversion
db.users.aggregate([
{
$project: {
age: {
$convert: {
input: "$age",
to: "int",
onError: 0,
onNull: 0
}
}
}
}
]);
// Convert with $cond
db.users.aggregate([
{
$project: {
age: {
$cond: {
if: { $eq: [{ $type: "$age" }, "string"] },
then: { $toInt: "$age" },
else: "$age"
}
}
}
}
]);
// Convert multiple fields
db.orders.aggregate([
{
$project: {
_id: 1,
amount: { $toDecimal: "$amount" },
quantity: { $toInt: "$quantity" }
}
}
]);Make HTTP requests using MongoDB Atlas Data API or application-level code.
- Atlas Data API: REST API to MongoDB
- MongoDB Stitch: Serverless platform
- Application code: Use HTTP client libraries
- Third-party: Use with drivers
// Loop through array (MongoDB)
// Using $map
db.users.aggregate([
{
$project: {
name: 1,
hobbiesUpperCase: {
$map: {
input: "$hobbies",
as: "hobby",
in: { $toUpper: "$$hobby" }
}
}
}
}
]);
// Using $filter
db.users.aggregate([
{
$project: {
name: 1,
hobbies: {
$filter: {
input: "$hobbies",
as: "hobby",
cond: { $ne: ["$$hobby", "gaming"] }
}
}
}
}
]);
// Using $reduce
db.users.aggregate([
{
$project: {
name: 1,
allHobbies: {
$reduce: {
input: "$hobbies",
initialValue: "",
in: { $concat: ["$$value", "$$this", ", "] }
}
}
}
}
]);
// Using $forEach (with JavaScript)
db.users.find().forEach(function(user) {
print("User: " + user.name);
user.hobbies.forEach(function(hobby) {
print(" - " + hobby);
});
});
// Using $unwind for iteration
db.users.aggregate([
{ $unwind: "$hobbies" },
{ $group: { _id: "$_id", hobbies: { $push: "$hobbies" } } }
]);Use JavaScript Promises with async/await in the mongo shell or application code.
- Promise:
new Promise((resolve, reject) => {}) - async/await:
async function() { await ... } - Callback: Traditional callback pattern
- Chaining:
then().catch()
// Delay function execution (MongoDB)
// Using sleep in JavaScript
function delayedExecution(delayMs, fn) {
sleep(delayMs);
fn();
}
// Using setTimeout in mongosh
var timeoutId = setTimeout(function() {
print("Executed after delay");
}, 2000);
// Clear timeout
clearTimeout(timeoutId);
// Using setInterval
var intervalId = setInterval(function() {
print("Repeating execution");
}, 1000);
// Clear interval
clearInterval(intervalId);
// Using $currentDate with delay
db.scheduledTasks.insertOne({
task: "processData",
scheduledAt: new Date(Date.now() + 60000)
});
// Polling for scheduled tasks
function processScheduledTasks() {
var tasks = db.scheduledTasks.find({
scheduledAt: { $lt: new Date() }
});
tasks.forEach(function(task) {
// Process task
print("Processing task: " + task.task);
db.scheduledTasks.deleteOne({ _id: task._id });
});
}
// Periodic check
setInterval(processScheduledTasks, 5000);Calculate factorial using JavaScript functions or aggregation.
- Recursive:
function fact(n) { return n <= 1 ? 1 : n * fact(n-1) } - Iterative: Loop with multiplication
- $reduce: Use
$rangeand$reduce - Stored function:
db.system.js.insert()
// HTTP GET request (MongoDB)
// Using MongoDB Atlas Data API
// GET request to MongoDB Atlas
fetch('https://data.mongodb-api.com/app/data-xxx/endpoint/data/v1/action/find', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api-key': 'your-api-key'
},
body: JSON.stringify({
dataSource: 'cluster0',
database: 'test',
collection: 'users',
filter: { status: 'active' }
})
})
.then(response => response.json())
.then(data => console.log(data));
// Using MongoDB Stitch (Realm)
const client = new Stitch.StitchAppClient('your-app-id');
const db = client.getServiceClient(Stitch.RemoteMongoClient.factory, 'mongodb-atlas');
// Query data
db.db('test').collection('users').find({}).toArray()
.then(users => console.log(users))
.catch(error => console.error(error));
// Using HTTP GET with MongoDB ReST API
const axios = require('axios');
axios.get('http://localhost:27017/test/users', {
auth: {
username: 'admin',
password: 'password'
}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));Calculate Fibonacci numbers using recursion, iteration, or memoization.
- Recursive:
function fib(n) { return n <= 1 ? n : fib(n-1) + fib(n-2) } - Iterative: Loop with variables
- Memoization: Cache results
- $reduce: Fibonacci with aggregation
// Create a promise-like Deferred (MongoDB)
// Using async/await in mongosh
function createDeferred(shouldResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldResolve) {
resolve("Success!");
} else {
reject("Failed!");
}
}, 1000);
});
}
// Usage
async function testDeferred() {
try {
var result = await createDeferred(true);
print(result);
} catch (error) {
print("Caught: " + error);
}
}
testDeferred();
// Using with MongoDB operations
async function findUser(userId) {
return await db.users.findOne({ _id: userId });
}
// Execute async
findUser("user123")
.then(user => printjson(user))
.catch(error => print("Error: " + error));
// Multiple async operations
async function processUsers() {
var users = await db.users.find({}).toArray();
for (var user of users) {
print("Processing: " + user.name);
}
}
processUsers();FizzBuzz using JavaScript loops or aggregation with $switch.
- JavaScript:
forloop with conditions - $switch:
{ $switch: { branches: [...] } } - $mod:
{ $mod: ["$num", 3] } - $function: Custom JavaScript in aggregation
// Factorial (MongoDB)
// Using JavaScript in mongosh
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
print(factorial(5)); // 120
// Iterative version
function factorialIterative(n) {
var result = 1;
for (var i = 2; i <= n; i++) {
result *= i;
}
return result;
}
// Using aggregation
db.numbers.aggregate([
{
$project: {
factorial: {
$reduce: {
input: { $range: [1, { $add: ["$n", 1] }] },
initialValue: 1,
in: { $multiply: ["$$value", "$$this"] }
}
}
}
}
]);
// Using stored function
db.system.js.insertOne({
_id: "factorial",
value: function(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
});
db.eval("factorial(5)"); // 120Find missing number using formula, XOR, or set difference in aggregation.
- Formula:
total - sum - $setDifference: Expected vs actual numbers
- $range: Generate expected numbers
- JavaScript: Custom function
// Fibonacci (MongoDB)
// Using JavaScript in mongosh
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
print(fibonacci(8)); // 21
// Iterative version
function fibonacciIterative(n) {
if (n <= 1) return n;
var a = 0, b = 1;
for (var i = 2; i <= n; i++) {
var temp = a + b;
a = b;
b = temp;
}
return b;
}
// Memoized version
var fibMemo = {};
function fibonacciMemo(n) {
if (n <= 1) return n;
if (fibMemo[n]) return fibMemo[n];
fibMemo[n] = fibonacciMemo(n - 1) + fibonacciMemo(n - 2);
return fibMemo[n];
}
// Using aggregation (for small n)
db.numbers.aggregate([
{
$project: {
fibonacci: {
$reduce: {
input: { $range: [0, { $add: ["$n", 1] }] },
initialValue: [0, 1],
in: {
$concatArrays: [
"$$value",
[
{
$add: [
{ $arrayElemAt: ["$$value", -1] },
{ $arrayElemAt: ["$$value", -2] }
]
}
]
]
}
}
}
}
}
]);Find duplicates using $group with $sum to count occurrences.
- $group:
{ _id: "$field", count: { $sum: 1 } } - $match:
{ count: { $gt: 1 } } - $facet: Multiple duplicate detection
- $push: Collect duplicate IDs
// FizzBuzz (MongoDB)
// Using JavaScript in mongosh
function fizzBuzz(n) {
for (var i = 1; i <= n; i++) {
if (i % 15 === 0) {
print("FizzBuzz");
} else if (i % 3 === 0) {
print("Fizz");
} else if (i % 5 === 0) {
print("Buzz");
} else {
print(i);
}
}
}
fizzBuzz(15);
// Using aggregation
db.numbers.insertMany(
Array.from({length: 15}, (_, i) => ({ num: i + 1 }))
);
db.numbers.aggregate([
{
$project: {
result: {
$switch: {
branches: [
{
case: { $eq: [{ $mod: ["$num", 15] }, 0] },
then: "FizzBuzz"
},
{
case: { $eq: [{ $mod: ["$num", 3] }, 0] },
then: "Fizz"
},
{
case: { $eq: [{ $mod: ["$num", 5] }, 0] },
then: "Buzz"
}
],
default: { $toString: "$num" }
}
}
}
}
]);
// Using $function (MongoDB 4.4+)
db.numbers.aggregate([
{
$project: {
result: {
$function: {
body: function(num) {
if (num % 15 === 0) return "FizzBuzz";
if (num % 3 === 0) return "Fizz";
if (num % 5 === 0) return "Buzz";
return String(num);
},
args: ["$num"],
lang: "js"
}
}
}
}
]);Calculate sum using $sum in $group or $project.
- $group:
{ $sum: "$field" } - $project:
{ total: { $sum: "$arrayField" } } - $reduce: Custom sum logic
- $unwind: Sum nested arrays
// Find missing number (MongoDB)
// Using JavaScript in mongosh
function findMissing(arr) {
var n = arr.length + 1;
var total = n * (n + 1) / 2;
var sum = arr.reduce((a, b) => a + b, 0);
return total - sum;
}
print(findMissing([1, 2, 4, 5, 6])); // 3
// Using aggregation
var numbers = [1, 2, 4, 5, 6];
db.numbers.insertMany(numbers.map(n => ({ num: n })));
db.numbers.aggregate([
{
$group: {
_id: null,
sum: { $sum: "$num" },
count: { $sum: 1 }
}
},
{
$project: {
missing: {
$subtract: [
{
$multiply: [
{ $divide: [{ $multiply: ["$count", { $add: ["$count", 1] }] }, 2] },
{ $add: ["$count", 1] }
]
},
"$sum"
]
}
}
}
]);
// Using $setUnion for missing numbers
db.numbers.aggregate([
{
$group: {
_id: null,
numbers: { $push: "$num" }
}
},
{
$project: {
numbers: 1,
expected: {
$range: [1, { $size: "$numbers" }]
}
}
},
{
$project: {
missing: {
$setDifference: ["$expected", "$numbers"]
}
}
}
]);Calculate average using $avg in $group or $project.
- $group:
{ $avg: "$field" } - $project:
{ average: { $avg: "$arrayField" } } - Weighted average:
{ $divide: [{ $sum: "$arrayField" }, { $size: "$arrayField" }] } - Nested arrays: Use
$unwind
// Find duplicates (MongoDB)
// Using aggregation
db.users.aggregate([
{
$group: {
_id: "$email",
count: { $sum: 1 },
docs: { $push: "$$ROOT" }
}
},
{
$match: { count: { $gt: 1 } }
}
]);
// Find duplicate emails
db.users.aggregate([
{
$group: {
_id: "$email",
count: { $sum: 1 }
}
},
{
$match: { count: { $gt: 1 } }
},
{
$project: {
email: "$_id",
count: 1,
_id: 0
}
}
]);
// Find duplicates in array
db.users.aggregate([
{
$project: {
name: 1,
duplicateHobbies: {
$reduce: {
input: "$hobbies",
initialValue: [],
in: {
$cond: [
{ $in: ["$$this", "$$value"] },
{ $concatArrays: ["$$value", ["$$this"]] },
"$$value"
]
}
}
}
}
}
]);
// Using $facet for duplicate detection
db.users.aggregate([
{
$facet: {
duplicates: [
{
$group: {
_id: "$email",
count: { $sum: 1 }
}
},
{ $match: { count: { $gt: 1 } } }
]
}
}
]);Sort using $sort in aggregation or sort() in find.
- $sort:
{ $sort: { field: 1 } } - Array sorting:
$sortArray(MongoDB 5.0+) - Multi-field sort:
{ field1: 1, field2: 1 } - With limit:
{ $limit: 10 }
// Sum of array (MongoDB)
// Using aggregation
db.orders.aggregate([
{
$group: {
_id: null,
total: { $sum: "$amount" }
}
}
]);
// Sum of array field
db.orders.aggregate([
{
$project: {
orderId: 1,
totalItems: { $sum: "$items.quantity" }
}
}
]);
// Sum with $reduce
db.orders.aggregate([
{
$project: {
total: {
$reduce: {
input: "$amounts",
initialValue: 0,
in: { $add: ["$$value", "$$this"] }
}
}
}
}
]);
// Sum of nested array
db.orders.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: "$_id",
total: { $sum: { $multiply: ["$items.price", "$items.quantity"] } }
}
}
]);
// Sum with $project
db.orders.aggregate([
{
$project: {
orderId: 1,
total: {
$sum: {
$map: {
input: "$items",
as: "item",
in: { $multiply: ["$$item.price", "$$item.quantity"] }
}
}
}
}
}
]);Sort descending using $sort with -1 or sort() with 'descend'.
- $sort:
{ $sort: { field: -1 } } - Array sorting:
$sortArraywith -1 - Multi-field:
{ field1: -1, field2: -1 } - With limit:
{ $limit: 10 }
// Average of array (MongoDB)
// Using aggregation
db.orders.aggregate([
{
$group: {
_id: null,
average: { $avg: "$amount" }
}
}
]);
// Average of array field
db.users.aggregate([
{
$project: {
name: 1,
averageScore: { $avg: "$scores" }
}
}
]);
// Average with $reduce
db.orders.aggregate([
{
$project: {
average: {
$divide: [
{
$reduce: {
input: "$amounts",
initialValue: 0,
in: { $add: ["$$value", "$$this"] }
}
},
{ $size: "$amounts" }
]
}
}
}
]);
// Weighted average
db.orders.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: "$_id",
weightedAverage: {
$divide: [
{ $sum: { $multiply: ["$items.price", "$items.quantity"] } },
{ $sum: "$items.quantity" }
]
}
}
}
]);
// Average of nested documents
db.orders.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: "$_id",
averagePrice: { $avg: "$items.price" }
}
}
]);Flatten nested arrays using $unwind multiple times or $reduce.
- $unwind:
{ $unwind: "$array" } - Multiple unwind: Multiple
$unwindstages - $reduce:
{ $concatArrays: [...] } - $project: With
$map
// Sort array ascending (MongoDB)
// Using $sort
db.users.aggregate([
{ $sort: { age: 1 } }
]);
// Sort with find
db.users.find().sort({ age: 1 });
// Sort nested field
db.orders.aggregate([
{ $sort: { "customer.name": 1 } }
]);
// Sort array field
db.users.aggregate([
{
$project: {
name: 1,
sortedHobbies: {
$sortArray: {
input: "$hobbies",
sortBy: 1
}
}
}
}
]);
// Sort array of objects
db.users.aggregate([
{
$project: {
name: 1,
sortedOrders: {
$sortArray: {
input: "$orders",
sortBy: { amount: 1 }
}
}
}
}
]);
// Multi-field sort
db.users.aggregate([
{ $sort: { age: 1, name: 1 } }
]);
// Sort with limit
db.users.find().sort({ age: 1 }).limit(10);Split array into chunks using $reduce, $slice, or JavaScript.
- $slice:
{ $slice: ["$array", start, size] } - $range: Generate indices
- $reduce: Custom chunking
- $function: JavaScript for chunking
// Sort array descending (MongoDB)
// Using $sort
db.users.aggregate([
{ $sort: { age: -1 } }
]);
// Sort with find
db.users.find().sort({ age: -1 });
// Sort nested field descending
db.orders.aggregate([
{ $sort: { "customer.name": -1 } }
]);
// Sort array field descending
db.users.aggregate([
{
$project: {
name: 1,
sortedHobbies: {
$sortArray: {
input: "$hobbies",
sortBy: -1
}
}
}
}
]);
// Sort array of objects descending
db.users.aggregate([
{
$project: {
name: 1,
sortedOrders: {
$sortArray: {
input: "$orders",
sortBy: { amount: -1 }
}
}
}
}
]);
// Sort with compound descending
db.users.aggregate([
{ $sort: { age: -1, name: -1 } }
]);
// Sort with limit descending
db.users.find().sort({ age: -1 }).limit(10);Binary search using JavaScript functions or indexes for efficient queries.
- JavaScript: Manual binary search
- Indexes:
createIndexfor efficient search - $search: Atlas Search for full-text
- Explain: Check index usage
// Flatten nested array (MongoDB)
// Using $unwind
db.users.aggregate([
{ $unwind: "$hobbies" },
{ $group: { _id: "$_id", hobbies: { $push: "$hobbies" } } }
]);
// Flatten with $project
db.users.aggregate([
{
$project: {
name: 1,
allItems: {
$reduce: {
input: "$nestedArray",
initialValue: [],
in: { $concatArrays: ["$$value", "$$this"] }
}
}
}
}
]);
// Flatten with $unwind multiple levels
db.users.aggregate([
{ $unwind: "$orders" },
{ $unwind: "$orders.items" },
{
$group: {
_id: "$_id",
allItems: { $push: "$orders.items" }
}
}
]);
// Flatten and unique
db.users.aggregate([
{ $unwind: "$hobbies" },
{
$group: {
_id: "$_id",
uniqueHobbies: { $addToSet: "$hobbies" }
}
}
]);
// Flatten nested arrays of objects
db.users.aggregate([
{ $unwind: "$orders" },
{ $unwind: "$orders.products" },
{
$group: {
_id: "$_id",
products: { $push: "$orders.products" }
}
}
]);Quick sort using JavaScript functions or aggregation with $sortArray.
- JavaScript: Recursive quick sort
- $sortArray:
{ $sortArray: { input: "$array", sortBy: 1 } } - $sort: Sort documents
- $function: Custom JavaScript sorting
// Chunk array (MongoDB)
// Using JavaScript in mongosh
function chunkArray(arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
}
printjson(chunkArray([1, 2, 3, 4, 5, 6], 2));
// Using aggregation
db.numbers.aggregate([
{
$project: {
chunk: {
$reduce: {
input: "$numbers",
initialValue: [],
in: {
$cond: [
{ $eq: [{ $mod: [{ $size: "$$value" }, 2] }, 0] },
{ $concatArrays: ["$$value", ["$$this"]] },
{ $concatArrays: ["$$value", ["$$this"]] }
]
}
}
}
}
}
]);
// Chunk using $slice
db.numbers.aggregate([
{
$project: {
chunks: {
$map: {
input: { $range: [0, { $size: "$numbers" }, 2] },
as: "start",
in: {
$slice: ["$numbers", "$$start", 2]
}
}
}
}
}
]);
// Chunk with custom size (using $function)
db.numbers.aggregate([
{
$project: {
chunks: {
$function: {
body: function(arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
},
args: ["$numbers", 2],
lang: "js"
}
}
}
}
]);Merge sort using JavaScript functions or aggregation with $sortArray.
- JavaScript: Recursive merge sort
- $sortArray:
{ $sortArray: { input: "$array", sortBy: 1 } } - $sort: Sort documents
- $function: Custom JavaScript sorting
// Binary search (MongoDB)
// Using JavaScript in mongosh
function binarySearch(arr, target) {
var left = 0;
var right = arr.length - 1;
while (left <= right) {
var mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
print(binarySearch([1, 2, 3, 4, 5, 6, 7], 5)); // 4
// Using aggregation
db.numbers.aggregate([
{
$project: {
found: {
$function: {
body: function(arr, target) {
var left = 0;
var right = arr.length - 1;
while (left <= right) {
var mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return true;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return false;
},
args: ["$numbers", 5],
lang: "js"
}
}
}
}
]);
// Binary search in MongoDB index
db.users.find({ age: 25 }).explain(); // Uses index if available
// $search with Atlas Search
db.users.aggregate([
{
$search: {
index: "default",
text: {
query: "Alice",
path: "name"
}
}
}
]);Bubble sort using JavaScript functions or $sortArray.
- JavaScript: Nested loops
- Optimized: Early termination
- $sortArray:
{ $sortArray: { input: "$array", sortBy: 1 } } - $function: Custom JavaScript sorting
// Quick sort (MongoDB)
// Using JavaScript in mongosh
function quickSort(arr) {
if (arr.length <= 1) return arr;
var pivot = arr[0];
var left = [];
var right = [];
for (var i = 1; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
printjson(quickSort([5, 3, 8, 4, 2, 7, 1, 6]));
// Using aggregation
db.numbers.aggregate([
{
$project: {
sorted: {
$function: {
body: function(arr) {
if (arr.length <= 1) return arr;
var pivot = arr[0];
var left = [];
var right = [];
for (var i = 1; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
},
args: ["$numbers"],
lang: "js"
}
}
}
}
]);
// Using $sort for arrays (MongoDB 5.0+)
db.users.aggregate([
{
$project: {
sortedHobbies: {
$sortArray: {
input: "$hobbies",
sortBy: 1
}
}
}
}
]);Find intersection using $setIntersection or $filter.
- $setIntersection:
{ $setIntersection: ["$arr1", "$arr2"] } - $filter:
{ $filter: { input: "$arr1", cond: { $in: ["$$item", "$arr2"] } } } - $reduce: Multiple arrays intersection
- JavaScript: Custom intersection
// Merge sort (MongoDB)
// Using JavaScript in mongosh
function mergeSort(arr) {
if (arr.length <= 1) return arr;
var mid = Math.floor(arr.length / 2);
var left = arr.slice(0, mid);
var right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
var result = [];
var i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return [...result, ...left.slice(i), ...right.slice(j)];
}
printjson(mergeSort([5, 3, 8, 4, 2, 7, 1, 6]));
// Using aggregation
db.numbers.aggregate([
{
$project: {
sorted: {
$function: {
body: function(arr) {
if (arr.length <= 1) return arr;
var mid = Math.floor(arr.length / 2);
var left = arr.slice(0, mid);
var right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right));
},
args: ["$numbers"],
lang: "js"
}
}
}
}
]);Find union using $setUnion or $concatArrays with $setUnion.
- $setUnion:
{ $setUnion: ["$arr1", "$arr2"] } - $concatArrays:
{ $concatArrays: ["$arr1", "$arr2"] } - $reduce: Multiple arrays union
- JavaScript: Custom union
// Bubble sort (MongoDB)
// Using JavaScript in mongosh
function bubbleSort(arr) {
var sorted = [...arr];
for (var i = 0; i < sorted.length - 1; i++) {
for (var j = 0; j < sorted.length - 1 - i; j++) {
if (sorted[j] > sorted[j + 1]) {
var temp = sorted[j];
sorted[j] = sorted[j + 1];
sorted[j + 1] = temp;
}
}
}
return sorted;
}
printjson(bubbleSort([5, 3, 8, 4, 2, 7, 1, 6]));
// Optimized bubble sort
function bubbleSortOptimized(arr) {
var sorted = [...arr];
for (var i = 0; i < sorted.length - 1; i++) {
var swapped = false;
for (var j = 0; j < sorted.length - 1 - i; j++) {
if (sorted[j] > sorted[j + 1]) {
var temp = sorted[j];
sorted[j] = sorted[j + 1];
sorted[j + 1] = temp;
swapped = true;
}
}
if (!swapped) break;
}
return sorted;
}
// Using aggregation with $function
db.numbers.aggregate([
{
$project: {
sorted: {
$function: {
body: function(arr) {
var sorted = [...arr];
for (var i = 0; i < sorted.length - 1; i++) {
for (var j = 0; j < sorted.length - 1 - i; j++) {
if (sorted[j] > sorted[j + 1]) {
var temp = sorted[j];
sorted[j] = sorted[j + 1];
sorted[j + 1] = temp;
}
}
}
return sorted;
},
args: ["$numbers"],
lang: "js"
}
}
}
}
]);Find difference using $setDifference or $filter.
- $setDifference:
{ $setDifference: ["$arr1", "$arr2"] } - $filter:
{ $filter: { input: "$arr1", cond: { $not: { $in: ["$$item", "$arr2"] } } } } - Symmetric difference: Union of differences
- JavaScript: Custom difference
// Intersection of arrays (MongoDB)
// Using aggregation
db.users.aggregate([
{
$project: {
name: 1,
commonHobbies: {
$setIntersection: ["$hobbies1", "$hobbies2"]
}
}
}
]);
// Intersection with $filter
db.users.aggregate([
{
$project: {
common: {
$filter: {
input: "$arr1",
as: "item",
cond: { $in: ["$$item", "$arr2"] }
}
}
}
}
]);
// Intersection of multiple arrays
db.users.aggregate([
{
$project: {
common: {
$setIntersection: ["$arr1", "$arr2", "$arr3"]
}
}
}
]);
// Using JavaScript in mongosh
function intersection(arr1, arr2) {
return arr1.filter(x => arr2.includes(x));
}
printjson(intersection([1, 2, 3, 4], [3, 4, 5, 6]));
// Using $reduce for intersection
db.users.aggregate([
{
$project: {
common: {
$reduce: {
input: "$arr1",
initialValue: "$arr2",
in: {
$filter: {
input: "$$value",
as: "item",
cond: { $in: ["$$item", "$$this"] }
}
}
}
}
}
}
]);Group by property using $group with $sum and $push.
- $group:
{ _id: "$field", count: { $sum: 1 } } - Multiple fields:
{ _id: { field1: "$f1", field2: "$f2" } } - $facet: Multiple group operations
- Nested fields:
{ _id: "$nested.field" }
// Union of arrays (MongoDB)
// Using $setUnion
db.users.aggregate([
{
$project: {
name: 1,
allHobbies: {
$setUnion: ["$hobbies1", "$hobbies2"]
}
}
}
]);
// Union with $concatArrays and $setUnion
db.users.aggregate([
{
$project: {
all: {
$setUnion: [
{ $concatArrays: ["$arr1", "$arr2"] }
]
}
}
}
]);
// Union of multiple arrays
db.users.aggregate([
{
$project: {
all: {
$setUnion: ["$arr1", "$arr2", "$arr3"]
}
}
}
]);
// Using JavaScript in mongosh
function union(arr1, arr2) {
return [...new Set([...arr1, ...arr2])];
}
printjson(union([1, 2, 3], [3, 4, 5]));
// Union with $reduce
db.users.aggregate([
{
$project: {
all: {
$reduce: {
input: ["$arr1", "$arr2", "$arr3"],
initialValue: [],
in: { $setUnion: ["$$value", "$$this"] }
}
}
}
}
]);Deep clone using JavaScript or JSON.parse(JSON.stringify()).
- JSON method:
JSON.parse(JSON.stringify(obj)) - Recursive: Custom clone function
- Spread operator:
{ ...obj }(shallow) - Object.assign:
Object.assign(, obj)(shallow)
// Difference of arrays (MongoDB)
// Using $setDifference
db.users.aggregate([
{
$project: {
name: 1,
diff: {
$setDifference: ["$arr1", "$arr2"]
}
}
}
]);
// Difference with $filter
db.users.aggregate([
{
$project: {
diff: {
$filter: {
input: "$arr1",
as: "item",
cond: { $not: { $in: ["$$item", "$arr2"] } }
}
}
}
}
]);
// Symmetric difference
db.users.aggregate([
{
$project: {
symmetricDiff: {
$setUnion: [
{ $setDifference: ["$arr1", "$arr2"] },
{ $setDifference: ["$arr2", "$arr1"] }
]
}
}
}
]);
// Using JavaScript in mongosh
function difference(arr1, arr2) {
return arr1.filter(x => !arr2.includes(x));
}
printjson(difference([1, 2, 3, 4], [3, 4, 5, 6]));
// Symmetric difference
function symmetricDifference(arr1, arr2) {
var diff1 = arr1.filter(x => !arr2.includes(x));
var diff2 = arr2.filter(x => !arr1.includes(x));
return [...diff1, ...diff2];
}
printjson(symmetricDifference([1, 2, 3], [3, 4, 5]));Immutable updates using $set to modify fields without overwriting entire documents.
- $set:
{ $set: { field: value } } - Nested fields:
{ $set: { "nested.field": value } } - $addToSet: Add to array if not exists
- $unset: Remove field
// Group by property (MongoDB)
// Using $group
db.users.aggregate([
{
$group: {
_id: "$city",
count: { $sum: 1 },
users: { $push: "$$ROOT" }
}
}
]);
// Group with multiple fields
db.orders.aggregate([
{
$group: {
_id: {
customerId: "$customerId",
status: "$status"
},
total: { $sum: "$amount" },
count: { $sum: 1 }
}
}
]);
// Group with $facet
db.orders.aggregate([
{
$facet: {
byCustomer: [
{
$group: {
_id: "$customerId",
total: { $sum: "$amount" }
}
}
],
byStatus: [
{
$group: {
_id: "$status",
count: { $sum: 1 }
}
}
]
}
}
]);
// Group by date
db.orders.aggregate([
{
$group: {
_id: {
year: { $year: "$createdAt" },
month: { $month: "$createdAt" }
},
total: { $sum: "$amount" }
}
}
]);
// Group by nested field
db.orders.aggregate([
{
$group: {
_id: "$customer.city",
total: { $sum: "$amount" }
}
}
]);Pipe using aggregation stages chained together or $facet for multiple pipelines.
- Aggregation: Chained stages
- $facet: Multiple parallel pipelines
- $unionWith: Combine pipelines
- $lookup: Join with pipeline
// Deep clone object (MongoDB)
// Using JavaScript in mongosh
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
var cloned = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
// Usage
var original = {
name: "Alice",
address: {
city: "NYC",
zip: "10001"
}
};
var cloned = deepClone(original);
cloned.name = "Bob";
print(original.name); // Alice
print(cloned.name); // Bob
// Using JSON methods (shallow clone for complex)
var shallowClone = JSON.parse(JSON.stringify(original));
// Using spread operator
var spreadClone = { ...original };
// Using Object.assign
var assignClone = Object.assign({}, original);
// Deep clone with MongoDB document
var doc = db.users.findOne({ _id: ObjectId() });
var clonedDoc = JSON.parse(JSON.stringify(doc));Function composition using multiple stages or JavaScript compose function.
- Stages:
db.collection.aggregate([stage1, stage2]) - $function:
{ $function: { body: compose(...) } } - JavaScript:
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x) - Chaining: Method chaining
// Immutable update (MongoDB)
// Using $set for updates
db.users.updateOne(
{ _id: "user123" },
{ $set: { "address.city": "LA" } }
);
// Immutable update with aggregation
db.users.aggregate([
{
$project: {
name: 1,
address: {
$mergeObjects: [
"$address",
{ city: "LA" }
]
}
}
}
]);
// Updating nested field immutably
db.users.updateOne(
{ _id: "user123" },
{
$set: {
"address.city": "LA",
"address.zip": "90001"
}
}
);
// Updating array immutably
db.users.updateOne(
{ _id: "user123" },
{ $addToSet: { hobbies: "reading" } }
);
// Removing field immutably
db.users.updateOne(
{ _id: "user123" },
{ $unset: { temporaryField: "" } }
);
// Multiple immutable updates
db.users.updateOne(
{ _id: "user123" },
{
$set: { "address.city": "LA" },
$inc: { age: 1 },
$push: { hobbies: "gaming" }
}
);Memoization using cache objects or MongoDB collection for persistent caching.
- Cache object:
const cache = - MongoDB cache: Store in collection
- TTL cache: With expiration
- Function:
function memoize(fn) { ... }
// Pipe function (MongoDB)
// Using aggregation pipeline
db.users.aggregate([
{
$match: { age: { $gte: 18 } }
},
{
$project: {
name: 1,
ageInDays: { $multiply: ["$age", 365] }
}
},
{
$sort: { age: -1 }
},
{
$limit: 10
}
]);
// Pipe using $facet
db.orders.aggregate([
{
$facet: {
totalRevenue: [
{ $group: { _id: null, total: { $sum: "$amount" } } }
],
topCustomers: [
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
]
}
}
]);
// Pipe using $unionWith
db.orders.aggregate([
{
$match: { status: "pending" }
},
{
$unionWith: {
coll: "archivedOrders",
pipeline: [
{ $match: { status: "pending" } }
]
}
}
]);
// Pipe using $lookup
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
},
{ $unwind: "$customer" },
{
$project: {
orderId: 1,
amount: 1,
customerName: "$customer.name"
}
}
]);Ensure a function is called only once using closure with a flag.
- Closure:
let called = false - MongoDB flag: Store in collection
- Lock: Prevent concurrent execution
- Module pattern: Encapsulate state
// Compose function (MongoDB)
// Using aggregation with $function
db.numbers.aggregate([
{
$project: {
result: {
$function: {
body: function(num) {
function double(x) { return x * 2; }
function addTen(x) { return x + 10; }
function square(x) { return x * x; }
var compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
var process = compose(square, addTen, double);
return process(num);
},
args: ["$num"],
lang: "js"
}
}
}
}
]);
// Compose using multiple stages
db.numbers.aggregate([
{
$project: {
value: { $multiply: ["$value", 2] } // double
}
},
{
$project: {
value: { $add: ["$value", 10] } // addTen
}
},
{
$project: {
value: { $pow: ["$value", 2] } // square
}
}
]);
// Function composition in JavaScript
function compose(...fns) {
return function(x) {
return fns.reduceRight((v, f) => f(v), x);
};
}
var double = x => x * 2;
var addTen = x => x + 10;
var square = x => x * x;
var process = compose(square, addTen, double);
print(process(5)); // 400Debounce with leading edge using timers and flag to track execution.
- Timer:
setTimeout - Leading edge: Execute immediately, then wait
- MongoDB: Store last execution time
- Application: Use in UI events
// Memoization (MongoDB)
// Using JavaScript in mongosh
function memoize(fn) {
var cache = {};
return function(arg) {
var key = JSON.stringify(arg);
if (cache[key] !== undefined) {
return cache[key];
}
var result = fn(arg);
cache[key] = result;
return result;
};
}
// Fibonacci with memoization
var fibMemo = memoize(function(n) {
if (n <= 1) return n;
return fibMemo(n - 1) + fibMemo(n - 2);
});
print(fibMemo(10));
// Using MongoDB for caching
function memoizeWithDB(fn, key) {
var cached = db.cache.findOne({ key: key });
if (cached) {
return cached.value;
}
var result = fn();
db.cache.insertOne({ key: key, value: result });
return result;
}
// Expiring cache
function memoizeWithTTL(fn, key, ttlSeconds) {
var cached = db.cache.findOne({ key: key });
if (cached && Date.now() - cached.timestamp < ttlSeconds * 1000) {
return cached.value;
}
var result = fn();
db.cache.updateOne(
{ key: key },
{ $set: { value: result, timestamp: Date.now() } },
{ upsert: true }
);
return result;
}Throttle with leading edge ensuring at most one execution per time period.
- Time check: Compare with last execution time
- Leading edge: Execute immediately if enough time passed
- MongoDB: Store last execution time
- Application: Rate limiting
// Once function (MongoDB)
// Using JavaScript in mongosh
function once(fn) {
var called = false;
var result = null;
return function() {
if (!called) {
called = true;
result = fn();
}
return result;
};
}
// Usage
var initialize = once(function() {
print("Initialized");
return { id: 1, name: "App" };
});
printjson(initialize()); // Prints "Initialized"
printjson(initialize()); // Returns cached result
// Using MongoDB for initialization tracking
function onceWithDB(fn, key) {
var initialized = db.initFlags.findOne({ key: key });
if (initialized) {
return initialized.value;
}
var result = fn();
db.initFlags.insertOne({ key: key, value: result });
return result;
}
// Once with lock for concurrent access
function onceWithLock(fn) {
var lock = false;
var result = null;
return function() {
if (!lock) {
lock = true;
result = fn();
}
return result;
};
}
// Module pattern for once initialization
var App = {
_initialized: false,
_data: null,
initialize: function(data) {
if (!this._initialized) {
this._data = data;
this._initialized = true;
}
return this._data;
}
};Deep equality using recursive comparison or JSON.stringify for simple cases.
- Recursive: Compare each property
- JSON:
JSON.stringify(obj1) === JSON.stringify(obj2) - $eq: In aggregation for fields
- Application: Use in validation
// Debounce with leading edge (MongoDB)
// Using JavaScript in mongosh
function debounceLeading(delayMs, fn) {
var lastCall = 0;
var timer = null;
return function() {
var now = Date.now();
if (now - lastCall < delayMs) {
if (timer) clearTimeout(timer);
timer = setTimeout(function() {
lastCall = Date.now();
fn();
}, delayMs);
} else {
lastCall = now;
fn();
}
};
}
// Usage
var debounced = debounceLeading(1000, function() {
print("Executed");
});
debounced(); // Executes immediately
debounced(); // Scheduled for later
// Using MongoDB with debounce
function debounceMongo(delayMs, fn, key) {
var lastCall = 0;
var timer = null;
return function() {
var now = Date.now();
if (now - lastCall < delayMs) {
if (timer) clearTimeout(timer);
timer = setTimeout(function() {
lastCall = Date.now();
fn();
}, delayMs);
} else {
lastCall = now;
fn();
}
};
}
// Debounce with database
function debounceWithDB(delayMs, fn, key) {
var timer = null;
return function() {
if (timer) clearTimeout(timer);
timer = setTimeout(function() {
db.debounced.updateOne(
{ key: key },
{ $set: { executed: new Date() } },
{ upsert: true }
);
fn();
}, delayMs);
};
}Observable pattern using change streams for real-time notifications.
- Change streams:
db.collection.watch() - Subscribers:
on("change", callback) - Custom observable: Implement with JavaScript
- Events: insert, update, delete
// Throttle with leading edge (MongoDB)
// Using JavaScript in mongosh
function throttleLeading(delayMs, fn) {
var lastCall = 0;
return function() {
var now = Date.now();
if (now - lastCall >= delayMs) {
lastCall = now;
fn();
}
};
}
// Usage
var throttled = throttleLeading(1000, function() {
print("Executed");
});
throttled(); // Executes
throttled(); // Ignored (within 1 second)
// Throttle with trailing edge
function throttleTrailing(delayMs, fn) {
var lastCall = 0;
var timer = null;
return function() {
var now = Date.now();
if (now - lastCall >= delayMs) {
lastCall = now;
fn();
} else if (!timer) {
timer = setTimeout(function() {
timer = null;
lastCall = Date.now();
fn();
}, delayMs - (now - lastCall));
}
};
}
// Throttle with MongoDB
function throttleMongo(delayMs, fn, key) {
var lastCall = 0;
return function() {
var now = Date.now();
if (now - lastCall >= delayMs) {
lastCall = now;
db.throttled.updateOne(
{ key: key },
{ $set: { lastExecuted: new Date() } },
{ upsert: true }
);
fn();
}
};
}Singleton pattern using module pattern or class with static instance.
- Module pattern: IIFE with private instance
- Class: Static getInstance method
- Global:
global.singleton = new Singleton() - MongoDB: Use for connection management
// Deep equal (MongoDB)
// Using JavaScript in mongosh
function deepEqual(obj1, obj2) {
if (obj1 === obj2) return true;
if (obj1 === null || obj2 === null) return false;
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
if (Array.isArray(obj1) !== Array.isArray(obj2)) return false;
if (Array.isArray(obj1)) {
if (obj1.length !== obj2.length) return false;
for (var i = 0; i < obj1.length; i++) {
if (!deepEqual(obj1[i], obj2[i])) return false;
}
return true;
}
var keys1 = Object.keys(obj1);
var keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (var key of keys1) {
if (!obj2.hasOwnProperty(key)) return false;
if (!deepEqual(obj1[key], obj2[key])) return false;
}
return true;
}
// Usage
var obj1 = { name: "Alice", address: { city: "NYC" } };
var obj2 = { name: "Alice", address: { city: "NYC" } };
print(deepEqual(obj1, obj2)); // true
// Using MongoDB comparison
db.users.findOne({ name: "Alice" })
.then(user1 => {
db.users.findOne({ name: "Alice" })
.then(user2 => {
var isEqual = JSON.stringify(user1) === JSON.stringify(user2);
print(isEqual);
});
});
// Deep equal with $eq
db.users.aggregate([
{
$project: {
isEqual: {
$eq: ["$address", "$savedAddress"]
}
}
}
]);Factory pattern using functions that create and return objects based on type.
- Factory function:
function createUser(type, data) { ... } - Switch/case: Create different object types
- Validation: Validate input before creation
- MongoDB: Create and insert documents
// Observable pattern (MongoDB)
// Using Change Streams
var changeStream = db.users.watch();
changeStream.on("change", function(change) {
print("Change detected!");
printjson(change);
});
// Observable with custom events
class Observable {
constructor() {
this.subscribers = [];
}
subscribe(callback) {
this.subscribers.push(callback);
return () => {
this.subscribers = this.subscribers.filter(cb => cb !== callback);
};
}
notify(data) {
this.subscribers.forEach(callback => callback(data));
}
}
// Usage
var observable = new Observable();
var unsubscribe = observable.subscribe(function(data) {
print("Received: " + JSON.stringify(data));
});
observable.notify({ message: "Hello" });
unsubscribe();
// Observable with MongoDB
function createObservable(collection) {
var changeStream = collection.watch();
var subscribers = [];
changeStream.on("change", function(change) {
subscribers.forEach(callback => callback(change));
});
return {
subscribe: function(callback) {
subscribers.push(callback);
return () => {
subscribers = subscribers.filter(cb => cb !== callback);
};
},
close: function() {
changeStream.close();
}
};
}
// Usage with collection
var userObservable = createObservable(db.users);
userObservable.subscribe(change => print("User change: " + change.operationType));Strategy pattern using functions or objects with different algorithms.
- Strategy functions: Different implementation
- Context: Uses strategy
- Dynamic switching: Change at runtime
- MongoDB: Different processing strategies
// Singleton pattern (MongoDB)
// Using module pattern
var Singleton = (function() {
var instance = null;
function createInstance() {
var data = {};
return {
set: function(key, value) {
data[key] = value;
},
get: function(key) {
return data[key];
},
getAll: function() {
return data;
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// Usage
var singleton1 = Singleton.getInstance();
var singleton2 = Singleton.getInstance();
singleton1.set("name", "Alice");
print(singleton2.get("name")); // Alice
// Singleton with MongoDB
var MongoSingleton = (function() {
var connection = null;
function createConnection() {
return db.getMongo();
}
return {
getConnection: function() {
if (!connection) {
connection = createConnection();
}
return connection;
}
};
})();
// Singleton for database
var DBManager = (function() {
var instance = null;
function createManager() {
return {
getCollection: function(name) {
return db.getCollection(name);
},
getDatabase: function() {
return db;
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = createManager();
}
return instance;
}
};
})();
// Usage
var manager1 = DBManager.getInstance();
var manager2 = DBManager.getInstance();
print(manager1 === manager2); // trueObserver pattern using change streams or custom event system.
- Change streams: Real-time notifications
- Custom events: Event emitter pattern
- Multiple collections: Watch multiple collections
- Filters: Match specific operations
// Factory pattern (MongoDB)
// Using JavaScript functions
function createUser(type, name) {
switch(type) {
case 'admin':
return {
type: 'admin',
name: name,
permissions: ['read', 'write', 'delete']
};
case 'guest':
return {
type: 'guest',
name: name,
permissions: ['read']
};
default:
return {
type: 'regular',
name: name,
permissions: ['read', 'write']
};
}
}
// Usage
var admin = createUser('admin', 'Alice');
printjson(admin);
// Factory with MongoDB insertion
function createUserInDB(type, name) {
var user = createUser(type, name);
db.users.insertOne(user);
return user;
}
// Factory with validation
function createValidatedUser(data) {
var required = ['name', 'email'];
for (var field of required) {
if (!data[field]) {
throw new Error('Missing required field: ' + field);
}
}
var user = {
_id: new ObjectId(),
name: data.name,
email: data.email,
age: data.age || null,
status: data.status || 'active',
createdAt: new Date()
};
return user;
}
// Factory pattern with inheritance
function UserFactory() {
this.create = function(type, data) {
switch(type) {
case 'customer':
return new Customer(data);
case 'employee':
return new Employee(data);
default:
throw new Error('Invalid user type');
}
};
}
function Customer(data) {
this.type = 'customer';
this.name = data.name;
this.accountNumber = data.accountNumber;
}
function Employee(data) {
this.type = 'employee';
this.name = data.name;
this.employeeId = data.employeeId;
}Decorator pattern using wrapper functions that enhance objects.
- Wrapper functions: Enhance functionality
- Chaining: Multiple decorators
- MongoDB: Enhance documents with metadata
- Validation: Validate decorated objects
// Strategy pattern (MongoDB)
// Using JavaScript functions
function createPaymentStrategy(type) {
switch(type) {
case 'credit':
return function(amount) {
print("Paid $" + amount + " with Credit Card");
};
case 'paypal':
return function(amount) {
print("Paid $" + amount + " with PayPal");
};
case 'crypto':
return function(amount) {
print("Paid $" + amount + " with Crypto");
};
default:
return function(amount) {
print("Paid $" + amount + " with Unknown method");
};
}
}
// Usage
var creditStrategy = createPaymentStrategy('credit');
var paypalStrategy = createPaymentStrategy('paypal');
creditStrategy(100);
paypalStrategy(50);
// Strategy with context
var PaymentContext = function(strategy) {
this.strategy = strategy;
this.execute = function(amount) {
this.strategy(amount);
};
};
// Usage
var context = new PaymentContext(creditStrategy);
context.execute(100);
// Strategy pattern with MongoDB
var ProcessStrategy = {
'insert': function(collection, data) {
return collection.insertOne(data);
},
'update': function(collection, filter, data) {
return collection.updateOne(filter, { $set: data });
},
'delete': function(collection, filter) {
return collection.deleteOne(filter);
}
};
function processData(collection, data, strategy) {
return ProcessStrategy[strategy](collection, data);
}
// Usage
processData(db.users, { name: "Alice" }, 'insert');
processData(db.users, { name: "Alice" }, 'delete');
// Strategy with aggregation
db.orders.aggregate([
{
$group: {
_id: {
$switch: {
branches: [
{ case: { $lt: ["$amount", 100] }, then: "small" },
{ case: { $lt: ["$amount", 500] }, then: "medium" }
],
default: "large"
}
},
count: { $sum: 1 }
}
}
]);Command pattern using objects with execute and undo methods.
- Command object: Execute and undo methods
- History: Stack of executed commands
- MongoDB: Database operations as commands
- Undo/Redo: Transaction support
// Observer pattern (MongoDB)
// Using Change Streams
var observer = {
onInsert: function(change) {
print("New document inserted: " + change.fullDocument._id);
},
onUpdate: function(change) {
print("Document updated: " + change.documentKey._id);
},
onDelete: function(change) {
print("Document deleted: " + change.documentKey._id);
}
};
var changeStream = db.users.watch();
changeStream.on("change", function(change) {
switch(change.operationType) {
case 'insert':
observer.onInsert(change);
break;
case 'update':
observer.onUpdate(change);
break;
case 'delete':
observer.onDelete(change);
break;
}
});
// Custom observable
var Observable = function() {
this.observers = [];
this.subscribe = function(observer) {
this.observers.push(observer);
return () => {
this.observers = this.observers.filter(o => o !== observer);
};
};
this.notify = function(data) {
this.observers.forEach(observer => observer(data));
};
};
// Observer pattern with multiple collections
var dbObserver = {
collections: {},
observe: function(collectionName) {
var changeStream = db[collectionName].watch();
this.collections[collectionName] = changeStream;
changeStream.on("change", function(change) {
print("Change on " + collectionName + ": " + change.operationType);
});
},
stopObserving: function(collectionName) {
if (this.collections[collectionName]) {
this.collections[collectionName].close();
delete this.collections[collectionName];
}
}
};
// Usage
dbObserver.observe('users');
dbObserver.observe('orders');
// Observer with pipeline filtering
var filteredStream = db.users.watch([
{
$match: {
operationType: 'insert'
}
}
]);
filteredStream.on("change", function(change) {
print("New user inserted: " + change.fullDocument.name);
});Memento pattern using snapshots of document state for recovery.
- Snapshot:
JSON.parse(JSON.stringify(doc)) - Restore:
db.collection.updateOne({ _id: id }, { $set: snapshot }) - History: Store multiple snapshots
- Version control: Document versioning
// Decorator pattern (MongoDB)
// Using JavaScript functions
function coffee() {
this.cost = 5.0;
this.description = "Coffee";
}
function milkDecorator(coffee) {
var decorated = Object.create(coffee);
decorated.cost = coffee.cost + 2.0;
decorated.description = coffee.description + ", Milk";
return decorated;
}
function sugarDecorator(coffee) {
var decorated = Object.create(coffee);
decorated.cost = coffee.cost + 1.0;
decorated.description = coffee.description + ", Sugar";
return decorated;
}
// Usage
var myCoffee = new coffee();
myCoffee = milkDecorator(myCoffee);
myCoffee = sugarDecorator(myCoffee);
print(myCoffee.description); // Coffee, Milk, Sugar
print(myCoffee.cost); // 8.0
// Decorator with MongoDB documents
function documentDecorator(doc) {
return {
...doc,
createdAt: new Date(),
updatedAt: new Date(),
toJSON: function() {
return {
...doc,
_id: doc._id.toString()
};
}
};
}
function timestampDecorator(doc) {
return {
...doc,
createdAt: new Date(),
updatedAt: new Date()
};
}
function logDecorator(doc, collection) {
return {
...doc,
log: function() {
print("Document inserted into " + collection);
}
};
}
// Usage
var user = { name: "Alice", age: 25 };
user = timestampDecorator(user);
user = logDecorator(user, "users");
db.users.insertOne(user);
user.log();
// Decorator with validation
function validateDecorator(schema, doc) {
for (var field in schema) {
if (schema[field].required && !doc[field]) {
throw new Error("Missing required field: " + field);
}
if (schema[field].type && typeof doc[field] !== schema[field].type) {
throw new Error("Invalid type for field: " + field);
}
}
return doc;
}Mediator pattern for centralized communication between components.
- Mediator: Centralized coordinator
- Colleagues: Communicate through mediator
- MongoDB: Database mediator for collections
- Decoupling: Reduce direct dependencies
// Command pattern (MongoDB)
// Using JavaScript functions
function AddCommand(receiver, value) {
this.receiver = receiver;
this.value = value;
this.execute = function() {
this.receiver.push(this.value);
print("Added: " + this.value);
};
this.undo = function() {
var index = this.receiver.indexOf(this.value);
if (index > -1) {
this.receiver.splice(index, 1);
print("Undo: Removed " + this.value);
}
};
}
// Usage
var receiver = [1, 2, 3];
var cmd = new AddCommand(receiver, 4);
cmd.execute();
printjson(receiver); // [1, 2, 3, 4]
cmd.undo();
printjson(receiver); // [1, 2, 3]
// Command pattern with MongoDB
function MongoCommand(collection, operation, data) {
this.collection = collection;
this.operation = operation;
this.data = data;
this.result = null;
this.execute = function() {
switch(this.operation) {
case 'insert':
this.result = this.collection.insertOne(this.data);
break;
case 'update':
this.result = this.collection.updateOne(
{ _id: this.data._id },
{ $set: this.data }
);
break;
case 'delete':
this.result = this.collection.deleteOne({ _id: this.data._id });
break;
}
return this.result;
};
this.undo = function() {
switch(this.operation) {
case 'insert':
this.collection.deleteOne({ _id: this.result.insertedId });
break;
case 'update':
// Revert to previous state (not implemented in this example)
break;
case 'delete':
this.collection.insertOne(this.data);
break;
}
};
}
// Command manager
var CommandManager = {
history: [],
execute: function(command) {
command.execute();
this.history.push(command);
},
undo: function() {
var command = this.history.pop();
if (command) {
command.undo();
}
}
};
// Usage
var insertCmd = new MongoCommand(db.users, 'insert', { name: "Alice" });
CommandManager.execute(insertCmd);
CommandManager.undo();Chain of Responsibility for sequential processing of requests.
- Handlers: Process or forward
- Chain: Linked list of handlers
- MongoDB: Validation chain, middleware
- Flexibility: Add/remove handlers
// Memento pattern (MongoDB)
// Using JavaScript functions
function Memento(state) {
this.state = state;
}
function Originator() {
this.state = null;
this.saveState = function() {
return new Memento(JSON.parse(JSON.stringify(this.state)));
};
this.restoreState = function(memento) {
this.state = memento.state;
print("State restored: " + JSON.stringify(this.state));
};
}
function Caretaker() {
this.mementos = [];
this.addMemento = function(memento) {
this.mementos.push(memento);
};
this.getMemento = function(index) {
return this.mementos[index];
};
}
// Usage
var originator = new Originator();
var caretaker = new Caretaker();
originator.state = { name: "State 1" };
caretaker.addMemento(originator.saveState());
originator.state = { name: "State 2" };
caretaker.addMemento(originator.saveState());
originator.state = { name: "State 3" };
originator.restoreState(caretaker.getMemento(0));
print(originator.state.name); // State 1
// Memento with MongoDB
function MongoMemento(collection, documentId) {
this.documentId = documentId;
this.snapshot = null;
this.save = function() {
var doc = collection.findOne({ _id: documentId });
this.snapshot = JSON.parse(JSON.stringify(doc));
return this;
};
this.restore = function() {
collection.updateOne(
{ _id: this.documentId },
{ $set: this.snapshot }
);
return this;
};
}
// Memento manager
var SnapshotManager = {
snapshots: {},
save: function(collection, id) {
var key = collection._name + ':' + id;
var doc = collection.findOne({ _id: id });
this.snapshots[key] = JSON.parse(JSON.stringify(doc));
print("Snapshot saved: " + key);
},
restore: function(collection, id) {
var key = collection._name + ':' + id;
var snapshot = this.snapshots[key];
if (snapshot) {
collection.updateOne(
{ _id: id },
{ $set: snapshot }
);
print("Snapshot restored: " + key);
}
}
};
// Usage
db.users.insertOne({ _id: "user123", name: "Alice", age: 25 });
SnapshotManager.save(db.users, "user123");
db.users.updateOne({ _id: "user123" }, { $set: { age: 26 } });
SnapshotManager.restore(db.users, "user123");State pattern for managing object state transitions.
- State object: Behavior depends on state
- Transitions: Allowed state changes
- MongoDB: Document status field
- Validation: Validate state transitions
// Mediator pattern (MongoDB)
// Using JavaScript functions
function Mediator() {
this.colleagues = [];
this.register = function(colleague) {
this.colleagues.push(colleague);
colleague.mediator = this;
};
this.send = function(message, sender) {
this.colleagues.forEach(function(colleague) {
if (colleague !== sender) {
colleague.receive(message);
}
});
};
}
function Colleague(name) {
this.name = name;
this.mediator = null;
this.send = function(message) {
if (this.mediator) {
this.mediator.send(message, this);
}
};
this.receive = function(message) {
print(this.name + " received: " + message);
};
}
// Usage
var mediator = new Mediator();
var alice = new Colleague("Alice");
var bob = new Colleague("Bob");
mediator.register(alice);
mediator.register(bob);
alice.send("Hello Bob!");
// Mediator with MongoDB
var DatabaseMediator = {
collections: {},
register: function(name, collection) {
this.collections[name] = collection;
},
query: function(collectionName, query) {
if (this.collections[collectionName]) {
return this.collections[collectionName].find(query).toArray();
}
return [];
},
insert: function(collectionName, data) {
if (this.collections[collectionName]) {
return this.collections[collectionName].insertOne(data);
}
return null;
},
update: function(collectionName, filter, data) {
if (this.collections[collectionName]) {
return this.collections[collectionName].updateOne(filter, { $set: data });
}
return null;
},
delete: function(collectionName, filter) {
if (this.collections[collectionName]) {
return this.collections[collectionName].deleteOne(filter);
}
return null;
}
};
// Usage
DatabaseMediator.register('users', db.users);
DatabaseMediator.register('orders', db.orders);
var users = DatabaseMediator.query('users', {});
printjson(users);
DatabaseMediator.insert('users', { name: "Alice", age: 25 });
DatabaseMediator.update('users', { name: "Alice" }, { age: 26 });
DatabaseMediator.delete('users', { name: "Alice" });Proxy pattern for controlling access to objects.
- Proxy: Controls access
- Real object: Actual implementation
- Lazy loading: Load on demand
- MongoDB: Query proxy, cache proxy
// Chain of Responsibility (MongoDB)
// Using JavaScript functions
function Handler() {
this.nextHandler = null;
this.setNext = function(handler) {
this.nextHandler = handler;
return handler;
};
this.handle = function(request) {
if (this.nextHandler) {
return this.nextHandler.handle(request);
}
return null;
};
}
function AuthHandler() {
this.handle = function(request) {
if (request.token) {
print("Authentication passed");
if (this.nextHandler) {
return this.nextHandler.handle(request);
}
} else {
print("Authentication failed");
return null;
}
};
}
AuthHandler.prototype = Object.create(Handler.prototype);
function LoggerHandler() {
this.handle = function(request) {
print("Logging request: " + request.url);
if (this.nextHandler) {
return this.nextHandler.handle(request);
}
return null;
};
}
LoggerHandler.prototype = Object.create(Handler.prototype);
function PermissionHandler() {
this.handle = function(request) {
if (request.permissions && request.permissions.includes('read')) {
print("Permission granted");
if (this.nextHandler) {
return this.nextHandler.handle(request);
}
} else {
print("Permission denied");
return null;
}
};
}
PermissionHandler.prototype = Object.create(Handler.prototype);
// Usage
var auth = new AuthHandler();
var logger = new LoggerHandler();
var permission = new PermissionHandler();
auth.setNext(logger).setNext(permission);
auth.handle({
token: "valid",
url: "/api/data",
permissions: ['read']
});
// Chain with MongoDB
var ValidationChain = {
steps: [],
addStep: function(step) {
this.steps.push(step);
return this;
},
validate: function(document) {
var result = document;
for (var step of this.steps) {
result = step(result);
if (!result) {
print("Validation failed at " + step.name);
return null;
}
}
return result;
}
};
// Usage
function requiredFields(fields) {
return function(doc) {
for (var field of fields) {
if (!doc[field]) {
print("Missing field: " + field);
return null;
}
}
return doc;
};
}
function validateTypes(schema) {
return function(doc) {
for (var field in schema) {
if (doc[field] && typeof doc[field] !== schema[field]) {
print("Invalid type for " + field);
return null;
}
}
return doc;
};
}
var validator = ValidationChain
.addStep(requiredFields(['name', 'email']))
.addStep(validateTypes({ name: 'string', age: 'number' }));
var validDoc = validator.validate({ name: "Alice", email: "alice@example.com", age: 25 });
var invalidDoc = validator.validate({ name: "Bob", age: "25" });Flyweight pattern for sharing objects to save memory.
- Flyweight: Shared object
- Factory: Manages flyweights
- MongoDB: Shared schemas, cached documents
- Performance: Memory optimization
// State pattern (MongoDB)
// Using JavaScript functions
function State() {
this.handle = function() {};
}
function ReadyState() {
this.handle = function() {
print("Ready: Waiting for input");
};
}
ReadyState.prototype = Object.create(State.prototype);
function ProcessingState() {
this.handle = function() {
print("Processing: Working on task");
};
}
ProcessingState.prototype = Object.create(State.prototype);
function CompletedState() {
this.handle = function() {
print("Completed: Task finished");
};
}
CompletedState.prototype = Object.create(State.prototype);
function Context() {
this.state = new ReadyState();
this.setState = function(state) {
this.state = state;
};
this.request = function() {
this.state.handle();
};
}
// Usage
var context = new Context();
context.request(); // Ready: Waiting for input
context.setState(new ProcessingState());
context.request(); // Processing: Working on task
context.setState(new CompletedState());
context.request(); // Completed: Task finished
// State pattern with MongoDB
function OrderState() {
this.status = 'pending';
this.transitions = {};
this.canTransition = function(newState) {
return this.transitions[this.status] &&
this.transitions[this.status].includes(newState);
};
this.transition = function(newState) {
if (this.canTransition(newState)) {
this.status = newState;
print("Order status changed to: " + newState);
return true;
}
print("Invalid transition from " + this.status + " to " + newState);
return false;
};
}
// Order state with allowed transitions
var orderState = new OrderState();
orderState.transitions = {
'pending': ['processing', 'cancelled'],
'processing': ['shipped', 'cancelled'],
'shipped': ['delivered', 'returned'],
'delivered': ['returned']
};
// Usage
orderState.transition('processing');
orderState.transition('shipped');
orderState.transition('delivered');
// State in MongoDB document
db.orders.insertOne({
_id: "order123",
status: "pending",
transitions: [
{ from: "pending", to: "processing", timestamp: new Date() }
]
});
db.orders.updateOne(
{ _id: "order123", status: "pending" },
{
$set: { status: "processing" },
$push: { transitions: { from: "pending", to: "processing", timestamp: new Date() } }
}
);Bridge pattern for separating abstraction from implementation.
- Abstraction: High-level interface
- Implementation: Low-level operations
- MongoDB: Repository pattern, data access
- Flexibility: Change implementation
// Proxy pattern (MongoDB)
// Using JavaScript functions
function RealSubject() {
this.request = function() {
print("RealSubject: Handling request");
};
}
function Proxy() {
this.realSubject = null;
this.request = function() {
if (this.checkAccess()) {
if (!this.realSubject) {
this.realSubject = new RealSubject();
}
this.realSubject.request();
this.logAccess();
}
};
this.checkAccess = function() {
print("Proxy: Checking access");
return true;
};
this.logAccess = function() {
print("Proxy: Logging access");
};
}
// Usage
var proxy = new Proxy();
proxy.request();
// Proxy with MongoDB
function MongoProxy(collection) {
this.collection = collection;
this.cache = {};
this.find = function(filter) {
var key = JSON.stringify(filter);
if (this.cache[key]) {
print("Cache hit for: " + key);
return this.cache[key];
}
print("Cache miss for: " + key);
var result = this.collection.find(filter).toArray();
this.cache[key] = result;
return result;
};
this.insert = function(data) {
print("Inserting: " + JSON.stringify(data));
var result = this.collection.insertOne(data);
// Invalidate cache
this.cache = {};
return result;
};
this.clearCache = function() {
this.cache = {};
print("Cache cleared");
};
}
// Usage
var proxy = new MongoProxy(db.users);
proxy.find({ age: { $gt: 18 } });
proxy.find({ age: { $gt: 18 } }); // Cache hit
proxy.insert({ name: "Alice", age: 25 });
proxy.find({ age: { $gt: 18 } }); // Cache miss (cache cleared)
// Virtual proxy (lazy loading)
function VirtualProxy(collection, id) {
this.collection = collection;
this.id = id;
this.realObject = null;
this.get = function() {
if (!this.realObject) {
print("Loading document from database");
this.realObject = this.collection.findOne({ _id: this.id });
}
return this.realObject;
};
}
// Usage
var proxy2 = new VirtualProxy(db.users, "user123");
var user = proxy2.get(); // Loads from DB
var user2 = proxy2.get(); // Returns cached objectAdapter pattern for converting interfaces.
- Adapter: Converts interface
- Adaptee: Existing interface
- MongoDB: SQL to MongoDB adapter
- Compatibility: Make incompatible classes work
// Flyweight pattern (MongoDB)
// Using JavaScript functions
function Flyweight(sharedState) {
this.sharedState = sharedState;
this.operation = function(uniqueState) {
print("Shared: " + this.sharedState + ", Unique: " + uniqueState);
};
}
function FlyweightFactory() {
this.flyweights = {};
this.getFlyweight = function(sharedState) {
var key = JSON.stringify(sharedState);
if (!this.flyweights[key]) {
this.flyweights[key] = new Flyweight(sharedState);
print("Creating new flyweight for: " + sharedState);
}
return this.flyweights[key];
};
}
// Usage
var factory = new FlyweightFactory();
var fw1 = factory.getFlyweight("state1");
var fw2 = factory.getFlyweight("state1");
var fw3 = factory.getFlyweight("state2");
fw1.operation("unique1");
fw2.operation("unique2");
fw3.operation("unique3");
// Flyweight with MongoDB
function DocumentFlyweight(schema) {
this.schema = schema;
this.cache = {};
this.getDocument = function(data) {
var key = JSON.stringify(data);
if (this.cache[key]) {
return this.cache[key];
}
var doc = {};
for (var field in this.schema) {
doc[field] = data[field] || this.schema[field].default || null;
}
this.cache[key] = doc;
return doc;
};
}
// Usage
var userSchema = {
name: { type: 'string', default: 'Unknown' },
age: { type: 'number', default: 0 },
city: { type: 'string', default: 'Unknown' }
};
var flyweight = new DocumentFlyweight(userSchema);
var doc1 = flyweight.getDocument({ name: "Alice", age: 25 });
var doc2 = flyweight.getDocument({ name: "Alice", age: 25 });
print(doc1 === doc2); // true (same object)
// Flyweight for repeated values
function ArrayFlyweight() {
this.cache = {};
this.getArray = function(values) {
var key = values.join(',');
if (!this.cache[key]) {
this.cache[key] = values;
}
return this.cache[key];
};
}
// Usage
var arrayFactory = new ArrayFlyweight();
var arr1 = arrayFactory.getArray([1, 2, 3]);
var arr2 = arrayFactory.getArray([1, 2, 3]);
print(arr1 === arr2); // trueFacade pattern for simplifying complex subsystems.
- Facade: Simplified interface
- Subsystem: Complex components
- MongoDB: Database facade, query builder
- Simplicity: Hide complexity
// Bridge pattern (MongoDB)
// Using JavaScript functions
function Implementation() {
this.operation = function() {};
}
function ConcreteImplementationA() {
this.operation = function() {
print("ConcreteImplementationA: Operation");
};
}
ConcreteImplementationA.prototype = Object.create(Implementation.prototype);
function ConcreteImplementationB() {
this.operation = function() {
print("ConcreteImplementationB: Operation");
};
}
ConcreteImplementationB.prototype = Object.create(Implementation.prototype);
function Abstraction(impl) {
this.impl = impl;
this.operation = function() {
print("Abstraction: Additional logic");
this.impl.operation();
};
}
// Usage
var implA = new ConcreteImplementationA();
var implB = new ConcreteImplementationB();
var abstraction1 = new Abstraction(implA);
var abstraction2 = new Abstraction(implB);
abstraction1.operation();
abstraction2.operation();
// Bridge with MongoDB
function MongoImplementation() {
this.collection = null;
this.query = function() {};
this.insert = function() {};
this.update = function() {};
this.delete = function() {};
}
function UserImplementation() {
this.collection = db.users;
this.query = function(filter) {
return this.collection.find(filter).toArray();
};
this.insert = function(data) {
return this.collection.insertOne(data);
};
this.update = function(filter, data) {
return this.collection.updateOne(filter, { $set: data });
};
this.delete = function(filter) {
return this.collection.deleteOne(filter);
};
}
UserImplementation.prototype = Object.create(MongoImplementation.prototype);
function OrderImplementation() {
this.collection = db.orders;
this.query = function(filter) {
return this.collection.find(filter).toArray();
};
this.insert = function(data) {
return this.collection.insertOne(data);
};
this.update = function(filter, data) {
return this.collection.updateOne(filter, { $set: data });
};
this.delete = function(filter) {
return this.collection.deleteOne(filter);
};
}
OrderImplementation.prototype = Object.create(MongoImplementation.prototype);
function Repository(impl) {
this.impl = impl;
this.findAll = function() {
return this.impl.query({});
};
this.findById = function(id) {
return this.impl.query({ _id: id });
};
this.save = function(data) {
return this.impl.insert(data);
};
this.update = function(id, data) {
return this.impl.update({ _id: id }, data);
};
this.delete = function(id) {
return this.impl.delete({ _id: id });
};
}
// Usage
var userRepo = new Repository(new UserImplementation());
var orderRepo = new Repository(new OrderImplementation());
userRepo.save({ name: "Alice", age: 25 });
orderRepo.save({ customerId: "user123", amount: 100 });Composite pattern for tree structures.
- Component: Interface for all
- Leaf: Individual object
- Composite: Container
- MongoDB: Schema composition, nested documents
// Adapter pattern (MongoDB)
// Using JavaScript functions
function Target() {
this.request = function() {
print("Target: Request");
};
}
function Adaptee() {
this.specificRequest = function() {
print("Adaptee: Specific Request");
};
}
function Adapter(adaptee) {
this.adaptee = adaptee;
this.request = function() {
this.adaptee.specificRequest();
};
}
// Usage
var adaptee = new Adaptee();
var adapter = new Adapter(adaptee);
adapter.request();
// Adapter with MongoDB
function MongoDBAdapter() {
this.db = db;
// Adapter methods
this.find = function(collection, query) {
return this.db[collection].find(query).toArray();
};
this.insert = function(collection, data) {
return this.db[collection].insertOne(data);
};
this.update = function(collection, filter, data) {
return this.db[collection].updateOne(filter, { $set: data });
};
this.delete = function(collection, filter) {
return this.db[collection].deleteOne(filter);
};
}
// SQL to MongoDB adapter
function SQLtoMongoAdapter() {
this.select = function(collection, fields) {
var projection = {};
fields.forEach(function(field) {
projection[field] = 1;
});
return { collection: collection, projection: projection };
};
this.where = function(query, conditions) {
query.filter = conditions;
return query;
};
this.orderBy = function(query, field, direction) {
query.sort = {};
query.sort[field] = direction === 'desc' ? -1 : 1;
return query;
};
this.limit = function(query, count) {
query.limit = count;
return query;
};
this.execute = function(query) {
var cursor = db[query.collection].find(query.filter || {});
if (query.projection) {
cursor = cursor.project(query.projection);
}
if (query.sort) {
cursor = cursor.sort(query.sort);
}
if (query.limit) {
cursor = cursor.limit(query.limit);
}
return cursor.toArray();
};
}
// Usage
var adapter = new SQLtoMongoAdapter();
var query = adapter.select('users', ['name', 'age']);
query = adapter.where(query, { age: { $gt: 18 } });
query = adapter.orderBy(query, 'name', 'asc');
query = adapter.limit(query, 10);
var results = adapter.execute(query);
printjson(results);
// API adapter
function RestAPIAdapter() {
this.get = function(collection, id) {
return db[collection].findOne({ _id: id });
};
this.post = function(collection, data) {
return db[collection].insertOne(data);
};
this.put = function(collection, id, data) {
return db[collection].updateOne({ _id: id }, { $set: data });
};
this.delete = function(collection, id) {
return db[collection].deleteOne({ _id: id });
};
}Visitor pattern for adding operations without modifying elements.
- Visitor: Defines operations
- Element: Accepts visitors
- MongoDB: Document visitor, validation visitor
- Extensibility: Add operations easily
// Facade pattern (MongoDB)
// Using JavaScript functions
function SubsystemA() {
this.operationA = function() {
print("SubsystemA: Operation");
};
}
function SubsystemB() {
this.operationB = function() {
print("SubsystemB: Operation");
};
}
function Facade() {
this.subsystemA = new SubsystemA();
this.subsystemB = new SubsystemB();
this.operation = function() {
this.subsystemA.operationA();
this.subsystemB.operationB();
print("Facade: Complex operation");
};
}
// Usage
var facade = new Facade();
facade.operation();
// Facade with MongoDB
function DatabaseFacade() {
this.insertUser = function(userData) {
return db.users.insertOne({
...userData,
createdAt: new Date(),
status: 'active'
});
};
this.findUser = function(id) {
return db.users.findOne({ _id: id });
};
this.updateUser = function(id, userData) {
return db.users.updateOne(
{ _id: id },
{ $set: { ...userData, updatedAt: new Date() } }
);
};
this.deleteUser = function(id) {
return db.users.updateOne(
{ _id: id },
{ $set: { status: 'deleted', deletedAt: new Date() } }
);
};
this.getUserOrders = function(userId) {
return db.orders.find({ userId: userId }).toArray();
};
this.createOrder = function(orderData) {
return db.orders.insertOne({
...orderData,
createdAt: new Date(),
status: 'pending'
});
};
this.getUserWithOrders = function(userId) {
var user = this.findUser(userId);
var orders = this.getUserOrders(userId);
return { ...user, orders: orders };
};
}
// Usage
var dbFacade = new DatabaseFacade();
var result = dbFacade.insertUser({ name: "Alice", age: 25 });
var user = dbFacade.findUser(result.insertedId);
var orders = dbFacade.getUserOrders(user._id);
// Analytics facade
function AnalyticsFacade() {
this.getUserStats = function() {
return db.users.aggregate([
{
$group: {
_id: null,
totalUsers: { $sum: 1 },
averageAge: { $avg: "$age" },
byCity: { $push: "$city" }
}
}
]).toArray();
};
this.getOrderStats = function() {
return db.orders.aggregate([
{
$group: {
_id: "$status",
count: { $sum: 1 },
totalRevenue: { $sum: "$amount" }
}
}
]).toArray();
};
this.getUserActivity = function(userId) {
return db.audit.find({ userId: userId, action: 'login' }).toArray();
};
}
// Usage
var analytics = new AnalyticsFacade();
var userStats = analytics.getUserStats();
var orderStats = analytics.getOrderStats();Iterator pattern for sequential access to collections.
- Iterator: Traverses collection
- Aggregate: Creates iterator
- MongoDB: Cursor, custom iterator
- Pagination: Page through results
// Composite pattern (MongoDB)
// Using JavaScript functions
function Component() {
this.operation = function() {};
}
function Leaf(name) {
this.name = name;
this.operation = function() {
print("Leaf " + this.name + ": Operation");
};
}
Leaf.prototype = Object.create(Component.prototype);
function Composite(name) {
this.name = name;
this.children = [];
this.add = function(component) {
this.children.push(component);
};
this.remove = function(component) {
var index = this.children.indexOf(component);
if (index > -1) {
this.children.splice(index, 1);
}
};
this.operation = function() {
print("Composite " + this.name + ": Operation");
this.children.forEach(function(child) {
child.operation();
});
};
}
Composite.prototype = Object.create(Component.prototype);
// Usage
var leaf1 = new Leaf("A");
var leaf2 = new Leaf("B");
var composite = new Composite("Root");
composite.add(leaf1);
composite.add(leaf2);
composite.operation();
// Composite with MongoDB
function DocumentNode() {
this.data = null;
this.children = [];
this.setData = function(data) {
this.data = data;
};
this.addChild = function(child) {
this.children.push(child);
};
this.toJSON = function() {
if (this.children.length === 0) {
return this.data;
}
var result = { ...this.data };
this.children.forEach(function(child, index) {
result['child_' + index] = child.toJSON();
});
return result;
};
}
// Usage
var root = new DocumentNode();
root.setData({ name: "Root", type: "document" });
var child1 = new DocumentNode();
child1.setData({ name: "Child 1", type: "text" });
var child2 = new DocumentNode();
child2.setData({ name: "Child 2", type: "image" });
root.addChild(child1);
root.addChild(child2);
var json = root.toJSON();
printjson(json);
// Composite for database schema
function SchemaNode() {
this.fields = {};
this.subSchemas = {};
this.addField = function(name, type, options) {
this.fields[name] = { type: type, options: options || {} };
};
this.addSubSchema = function(name, schema) {
this.subSchemas[name] = schema;
};
this.toMongoSchema = function() {
var schema = {
bsonType: "object",
properties: {},
required: []
};
for (var field in this.fields) {
var fieldDef = this.fields[field];
schema.properties[field] = {
bsonType: fieldDef.type
};
if (fieldDef.options.required) {
schema.required.push(field);
}
}
for (var sub in this.subSchemas) {
schema.properties[sub] = this.subSchemas[sub].toMongoSchema();
}
return schema;
};
}
// Usage
var userSchema = new SchemaNode();
userSchema.addField('name', 'string', { required: true });
userSchema.addField('age', 'int', { required: false });
userSchema.addField('email', 'string', { required: true });
var addressSchema = new SchemaNode();
addressSchema.addField('street', 'string', { required: true });
addressSchema.addField('city', 'string', { required: true });
userSchema.addSubSchema('address', addressSchema);
var mongoSchema = userSchema.toMongoSchema();
printjson(mongoSchema);Template Method for algorithm skeletons.
- Abstract: Defines template
- Concrete: Implements steps
- MongoDB: Data processor, document processor
- Hooks: before/after callbacks
// Visitor pattern (MongoDB)
// Using JavaScript functions
function Visitor() {
this.visit = function(element) {};
}
function Element() {
this.accept = function(visitor) {};
}
function ElementA() {
this.accept = function(visitor) {
visitor.visit(this);
};
}
ElementA.prototype = Object.create(Element.prototype);
function ElementB() {
this.accept = function(visitor) {
visitor.visit(this);
};
}
ElementB.prototype = Object.create(Element.prototype);
function ConcreteVisitor() {
this.visitA = function(element) {
print("Visiting ElementA");
};
this.visitB = function(element) {
print("Visiting ElementB");
};
this.visit = function(element) {
if (element instanceof ElementA) {
this.visitA(element);
} else if (element instanceof ElementB) {
this.visitB(element);
}
};
}
// Usage
var visitor = new ConcreteVisitor();
var elementA = new ElementA();
var elementB = new ElementB();
elementA.accept(visitor);
elementB.accept(visitor);
// Visitor with MongoDB
function DocumentVisitor() {
this.visitInsert = function(doc) {
print("Inserting document: " + JSON.stringify(doc));
return db.collection.insertOne(doc);
};
this.visitUpdate = function(filter, update) {
print("Updating documents: " + JSON.stringify(filter));
return db.collection.updateMany(filter, { $set: update });
};
this.visitDelete = function(filter) {
print("Deleting documents: " + JSON.stringify(filter));
return db.collection.deleteMany(filter);
};
this.visitFind = function(filter) {
print("Finding documents: " + JSON.stringify(filter));
return db.collection.find(filter).toArray();
};
}
function DocumentCollection(collection) {
this.collection = collection;
this.accept = function(visitor, operation, data) {
switch(operation) {
case 'insert':
return visitor.visitInsert.call({ collection: this.collection }, data);
case 'update':
return visitor.visitUpdate.call({ collection: this.collection }, data.filter, data.update);
case 'delete':
return visitor.visitDelete.call({ collection: this.collection }, data);
case 'find':
return visitor.visitFind.call({ collection: this.collection }, data);
}
};
}
// Usage
var collection = new DocumentCollection(db.users);
var visitor = new DocumentVisitor();
collection.accept(visitor, 'insert', { name: "Alice" });
collection.accept(visitor, 'find', { name: "Alice" });
// Visitor for document validation
function ValidationVisitor() {
this.schema = null;
this.setSchema = function(schema) {
this.schema = schema;
};
this.visit = function(doc) {
if (!this.schema) {
print("No schema set");
return doc;
}
var validated = {};
for (var field in this.schema) {
if (this.schema[field].required && !doc[field]) {
throw new Error("Missing required field: " + field);
}
validated[field] = doc[field] || this.schema[field].default;
}
return validated;
};
}
// Usage
var validator = new ValidationVisitor();
validator.setSchema({
name: { required: true, default: 'Unknown' },
age: { required: false, default: 0 }
});
try {
var validDoc = validator.visit({ name: "Alice" });
printjson(validDoc);
var invalidDoc = validator.visit({}); // Throws error
} catch (error) {
print(error.message);
}Builder pattern for constructing complex objects.
- Builder: Constructs parts
- Director: Orchestrates construction
- MongoDB: Query builder, document builder
- Fluent interface: Method chaining
// Iterator pattern (MongoDB)
// Using JavaScript functions
function Iterator(collection) {
this.collection = collection;
this.index = 0;
this.next = function() {
if (this.hasNext()) {
return this.collection[this.index++];
}
return null;
};
this.hasNext = function() {
return this.index < this.collection.length;
};
}
function CustomCollection() {
this.items = [];
this.add = function(item) {
this.items.push(item);
};
this.getIterator = function() {
return new Iterator(this.items);
};
}
// Usage
var collection = new CustomCollection();
collection.add("A");
collection.add("B");
collection.add("C");
var iterator = collection.getIterator();
while (iterator.hasNext()) {
print(iterator.next());
}
// Iterator with MongoDB
function MongoIterator(collection, filter) {
this.cursor = collection.find(filter);
this.hasNext = function() {
return this.cursor.hasNext();
};
this.next = function() {
return this.cursor.next();
};
}
// Usage
var iterator = new MongoIterator(db.users, { age: { $gt: 18 } });
while (iterator.hasNext()) {
var user = iterator.next();
print(user.name);
}
// Custom cursor iterator
function CursorIterator(collection, query) {
this.cursor = collection.find(query).toArray();
this.index = 0;
this.next = function() {
if (this.hasNext()) {
return this.cursor[this.index++];
}
return null;
};
this.hasNext = function() {
return this.index < this.cursor.length;
};
}
// Usage
var iter = new CursorIterator(db.users, {});
while (iter.hasNext()) {
var doc = iter.next();
printjson(doc);
}
// Pagination iterator
function PaginatedIterator(collection, query, pageSize) {
this.collection = collection;
this.query = query;
this.pageSize = pageSize || 10;
this.currentPage = 0;
this.results = [];
this.total = 0;
this.index = 0;
this.loadPage = function() {
this.results = this.collection.find(this.query)
.skip(this.currentPage * this.pageSize)
.limit(this.pageSize)
.toArray();
this.index = 0;
this.total = this.collection.countDocuments(this.query);
};
this.next = function() {
if (this.index >= this.results.length) {
if ((this.currentPage + 1) * this.pageSize < this.total) {
this.currentPage++;
this.loadPage();
} else {
return null;
}
}
return this.results[this.index++];
};
this.hasNext = function() {
if (this.index < this.results.length) {
return true;
}
return (this.currentPage + 1) * this.pageSize < this.total;
};
this.loadPage();
}
// Usage
var paginated = new PaginatedIterator(db.users, { age: { $gt: 18 } }, 5);
while (paginated.hasNext()) {
var user = paginated.next();
print(user.name);
}Prototype pattern for cloning objects.
- Prototype: Cloneable object
- Clone: Creates a copy
- MongoDB: Document prototype, template documents
- Performance: Fast object creation
// Template Method pattern (MongoDB)
// Using JavaScript functions
function AbstractClass() {
this.templateMethod = function() {
this.step1();
this.step2();
this.step3();
};
this.step1 = function() {
print("Step 1");
};
this.step2 = function() {};
this.step3 = function() {
print("Step 3");
};
}
function ConcreteClass() {
this.step2 = function() {
print("Concrete Step 2");
};
}
ConcreteClass.prototype = Object.create(AbstractClass.prototype);
// Usage
var concrete = new ConcreteClass();
concrete.templateMethod();
// Template with MongoDB
function DataProcessor() {
this.process = function(data) {
this.validate(data);
this.transform(data);
this.save(data);
this.log(data);
};
this.validate = function(data) {
if (!data._id) {
data._id = new ObjectId();
}
return data;
};
this.transform = function(data) {
if (data.createdAt) {
data.createdAt = new Date(data.createdAt);
}
return data;
};
this.save = function(data) {
return db.collection.insertOne(data);
};
this.log = function(data) {
print("Processed document: " + data._id);
return data;
};
}
// Usage
var processor = new DataProcessor();
processor.process({ name: "Alice", age: 25 });
// Template with hooks
function DocumentProcessor(collection) {
this.collection = collection;
this.beforeValidate = function(data) { return data; };
this.afterValidate = function(data) { return data; };
this.beforeSave = function(data) { return data; };
this.afterSave = function(data) { return data; };
this.process = function(data) {
data = this.beforeValidate(data);
data = this.validate(data);
data = this.afterValidate(data);
data = this.beforeSave(data);
var result = this.save(data);
result = this.afterSave(result);
return result;
};
this.validate = function(data) {
if (!data.name) {
throw new Error("Name is required");
}
return data;
};
this.save = function(data) {
return this.collection.insertOne(data);
};
}
// Usage
var userProcessor = new DocumentProcessor(db.users);
userProcessor.beforeSave = function(data) {
data.createdAt = new Date();
return data;
};
userProcessor.afterSave = function(result) {
print("User saved with ID: " + result.insertedId);
return result;
};
userProcessor.process({ name: "Alice", age: 25 });Database design principles for MongoDB including normalization and denormalization.
- Embedded documents: One-to-one, one-to-many
- References: Many-to-many relationships
- Indexing: Create indexes for queries
- Schema validation: Enforce data structure
// Builder pattern (MongoDB)
// Using JavaScript functions
function Product() {
this.parts = [];
this.add = function(part) {
this.parts.push(part);
};
this.listParts = function() {
print(this.parts.join(', '));
};
}
function Builder() {
this.product = new Product();
this.reset = function() {
this.product = new Product();
};
this.buildStepA = function() {
this.product.add("Part A");
};
this.buildStepB = function() {
this.product.add("Part B");
};
this.getResult = function() {
return this.product;
};
}
function Director(builder) {
this.builder = builder;
this.buildMinimal = function() {
this.builder.buildStepA();
};
this.buildFull = function() {
this.builder.buildStepA();
this.builder.buildStepB();
};
}
// Usage
var builder = new Builder();
var director = new Director(builder);
director.buildMinimal();
var product = builder.getResult();
product.listParts();
// Builder with MongoDB
function QueryBuilder() {
this.query = {};
this.options = {};
this.collection = null;
this.from = function(collection) {
this.collection = collection;
return this;
};
this.where = function(filter) {
this.query = filter;
return this;
};
this.select = function(fields) {
this.options.projection = {};
fields.forEach(function(field) {
this.options.projection[field] = 1;
}, this);
return this;
};
this.limit = function(count) {
this.options.limit = count;
return this;
};
this.skip = function(count) {
this.options.skip = count;
return this;
};
this.sort = function(field, direction) {
this.options.sort = {};
this.options.sort[field] = direction === 'desc' ? -1 : 1;
return this;
};
this.execute = function() {
if (!this.collection) {
throw new Error("Collection not specified");
}
var cursor = this.collection.find(this.query);
if (this.options.projection) {
cursor = cursor.project(this.options.projection);
}
if (this.options.sort) {
cursor = cursor.sort(this.options.sort);
}
if (this.options.limit) {
cursor = cursor.limit(this.options.limit);
}
if (this.options.skip) {
cursor = cursor.skip(this.options.skip);
}
return cursor.toArray();
};
this.executeOne = function() {
return this.execute()[0] || null;
};
}
// Usage
var query = new QueryBuilder();
var results = query
.from(db.users)
.where({ age: { $gt: 18 } })
.select(['name', 'age'])
.sort('age', 'desc')
.limit(10)
.execute();
printjson(results);
// Document builder
function DocumentBuilder() {
this.doc = {};
this.set = function(key, value) {
this.doc[key] = value;
return this;
};
this.setNested = function(path, value) {
var parts = path.split('.');
var current = this.doc;
for (var i = 0; i < parts.length - 1; i++) {
if (!current[parts[i]]) {
current[parts[i]] = {};
}
current = current[parts[i]];
}
current[parts[parts.length - 1]] = value;
return this;
};
this.addToArray = function(key, value) {
if (!this.doc[key]) {
this.doc[key] = [];
}
this.doc[key].push(value);
return this;
};
this.timestamp = function() {
this.doc.createdAt = new Date();
this.doc.updatedAt = new Date();
return this;
};
this.build = function() {
return this.doc;
};
}
// Usage
var doc = new DocumentBuilder()
.set('name', 'Alice')
.set('age', 25)
.setNested('address.city', 'NYC')
.setNested('address.zip', '10001')
.addToArray('hobbies', 'reading')
.addToArray('hobbies', 'gaming')
.timestamp()
.build();
printjson(doc);
db.users.insertOne(doc);Query optimization techniques for MongoDB performance.
- Indexes: Create appropriate indexes
- Explain: Analyze query execution
- Projection: Return only needed fields
- Covered queries: Index-only queries
// Prototype pattern (MongoDB)
// Using JavaScript functions
function Prototype(name, nested) {
this.name = name;
this.nested = nested || {};
this.clone = function() {
return new Prototype(this.name, this.nested);
};
this.deepClone = function() {
return new Prototype(
this.name,
JSON.parse(JSON.stringify(this.nested))
);
};
}
// Usage
var original = new Prototype("Original", { value: 42 });
var copy = original.clone();
copy.name = "Copy";
copy.nested.value = 99;
print(original.name); // Original
print(original.nested.value); // 42 (shallow copy)
var deepCopy = original.deepClone();
deepCopy.nested.value = 100;
print(original.nested.value); // 42 (deep copy)
// Prototype with MongoDB
function DocumentPrototype(collection) {
this.collection = collection;
this.prototype = null;
this.setPrototype = function(doc) {
this.prototype = JSON.parse(JSON.stringify(doc));
return this;
};
this.create = function(overrides) {
if (!this.prototype) {
throw new Error("Prototype not set");
}
var doc = JSON.parse(JSON.stringify(this.prototype));
for (var key in overrides) {
doc[key] = overrides[key];
}
return doc;
};
this.insert = function(overrides) {
var doc = this.create(overrides);
return this.collection.insertOne(doc);
};
this.load = function(id) {
var doc = this.collection.findOne({ _id: id });
if (doc) {
this.setPrototype(doc);
}
return this;
};
}
// Usage
var prototype = new DocumentPrototype(db.users);
prototype.setPrototype({
name: "Default User",
age: 0,
status: "active",
createdAt: new Date(),
updatedAt: new Date()
});
var user1 = prototype.create({ name: "Alice", age: 25 });
var user2 = prototype.create({ name: "Bob", age: 30 });
db.users.insertMany([user1, user2]);
// Prototype with inheritance
function UserPrototype() {
this.name = "Unknown";
this.age = 0;
this.status = "active";
this.createdAt = new Date();
this.clone = function() {
return JSON.parse(JSON.stringify(this));
};
this.setName = function(name) {
this.name = name;
return this;
};
this.setAge = function(age) {
this.age = age;
return this;
};
}
// Usage
var userPrototype = new UserPrototype();
var user = userPrototype.clone();
user.name = "Alice";
user.age = 25;
// Prototype with factory
function UserFactory() {
this.prototype = new UserPrototype();
this.createUser = function(name, age) {
var user = this.prototype.clone();
user.name = name;
user.age = age;
return user;
};
}
// Usage
var factory = new UserFactory();
var alice = factory.createUser("Alice", 25);
var bob = factory.createUser("Bob", 30);
printjson(alice);
printjson(bob);