Mongodb Theory
Mongodb Theory
   MongoDB Basics
       o What is MongoDB ?
            1. MongoDB is an open-source NoSQL database.
            2. Document-based and cross-platform compatible.
            3. Offers high performance and high availability.
            4. Supports easy scalability for large data handling.
            5. Differs from relational databases by using a flexible, schema-less data
                model.
            6. Built on BSON (Binary JSON), allowing for efficient storage and
                querying of non-structured data.
       o Key Features of MongoDB ?
            1. Document-oriented: MongoDB stores data in JSON-like documents
                (BSON format). The flexible data model adapts to real-world object
                representations.
            2. Scalability: Offers automatic scaling. Can scale horizontally by
                sharding (partitioning data across servers) and vertically by adding
                storage.
            3. Indexing: Supports indexing on any document attribute to enhance
                query performance.
            4. Replication: Provides high availability through replica sets. Primary
                and secondary nodes maintain data copies.
            5. Aggregation: Features a powerful aggregation framework. Enables
                complex data operations like transformations, filtering, and sorting.
            6. Ad hoc queries: Supports searching by field, range, and regular
                expressions.
       o When we Use MongoDB ?
            1. Content Management Systems (CMS): MongoDB’s dynamic schema
                efficiently supports various content types, making it ideal for CMS
                needs.
            2. E-Commerce Platforms: With its scalability and flexibility,
                MongoDB handles complex product catalogs, customer data, and
                orders seamlessly.
            3. Social Networks: Designed to store large volumes of posts, user
                profiles, and interactions, MongoDB is well-suited for social media
                platforms.
            4. Real-Time Analytics: Equipped with aggregation and indexing,
                MongoDB enables the analysis and processing of live data for
                actionable insights.
            5. IoT Applications: MongoDB’s flexible data model captures and stores
                data from countless devices and sensors, a key requirement in IoT
                applications.
            6. Gaming: MongoDB manages player profiles, game progress, and other
                real-time data needed for a responsive gaming experience.
            7. Location-Based Services: With robust geospatial capabilities,
                MongoDB efficiently handles map data, locations, and geolocation
                queries.
       8. Big Data: MongoDB’s flexible model and horizontal scalability make
          it ideal for managing vast amounts of unstructured and semi-structured
          data.
       9. Mobile Applications: The flexible data model in MongoDB adapts
          well to the evolving data types and dynamic nature of mobile apps.
o   MongoDB Terminology ?
      1. Database: Holds collections and structures needed to manage data.
      2. Collection: A group of related documents, like a table in traditional
          databases.
      3. Document: A single record in a collection, made up of fields.
          Documents don’t need a fixed structure.
      4. Field: A piece of data in a document, similar to a column in a table.
      5. Index: A structure that speeds up searches, making data retrieval
          faster.
      6. Query: A way to get specific data from a collection based on
          conditions.
      7. Cursor: A pointer to the query result set, enabling efficient processing
          of individual documents.
      8. Aggregation: Summarizes and transforms data in collections for
          complex analysis or report generation.
      9. Replica Set: A group of MongoDB instances with the same data,
          providing redundancy, high availability, and automatic failover.
      10. Sharding: Distributes data across multiple machines to scale
          horizontally, breaking the dataset into manageable chunks called
          shards.
o   MongoDB Compass vs MongoDB Atlas
       
               1. MongoDB Compass
       
               2. MongoDB Atlas
 Schema-based Validation
           With Mongoose, you create a schema to define the rules for your data.
           For example, you can specify:
 Model-based Queries
           Once you define the schema, you create a model. This model helps
           you interact with the data in your MongoDB collection (e.g., adding,
           finding, updating, or deleting data).
          Adding Data: .save()
          Finding Data: .find(), .findOne()
          Updating Data: .updateOne()
          Deleting Data: .deleteOne()
 Middleware (Hooks)
    Mongoose lets you run custom logic before or after certain actions.
    For example:
    userSchema.pre('save', function(next) {
      console.log('Saving user:', this.name);
      next(); // Proceed to save the document.
    });
 Population
    Mongoose lets you link data from different collections. For example,
    you can link a User with their Posts. This is called population.
    User.findOne({ name:
    'Alice' }).populate('posts').then(user =>
    console.log(user));
 Query Building
 Aggregation
o Mongo export
o   mongodump
       mongodump is a MongoDB utility for creating database backups.
       Exports data into BSON (Binary JSON) format.
       Can back up entire databases or specific collections.
       Default output directory is ./dump (can be changed with -out).
       Use mongorestore to restore the backup.
       Basic Usage:
          mongodump --uri <MongoDB connection string>
          Common Use Cases:
mongorestore /path/to/backup
o   SQL vs NoSQL
       SQL
           BSON (Binary JSON) is the format MongoDB uses to store data. In addition
           to standard JSON types, BSON supports:
               Date
              0.
                   Stores dates as milliseconds since the Unix epoch.
            1. Binary Data
                   Stores binary content like images, videos, or files.
            2. ObjectId
                   Unique 12-byte identifier automatically generated for each
                     document.
            3. Decimal128
                   High-precision decimal type for monetary or scientific
                     calculations.
            4. Code
                   Stores JavaScript code within documents.
            5. Regular Expression
                   Stores regex patterns directly in documents.
            6. MinKey/MaxKey
                   Special types to compare values in a query.
   Embedded Documents and Arrays
           You can easily query embedded arrays using MongoDB’s array query
           operators, like $elemMatch, **$all**, and **$size**. You can also use dot
           notation to search and update embedded documents.
 Example Query:
                  {
                      "addressId": 101,
                      "street": "123 Main St",
                      "city": "Springfield"
                  }
               Advantages:
                     No size limits.
                     Better for frequently updated data.
             Disadvantages:
                     Slower reads (requires additional queries).
                     More complex queries.
   Data Model and Data Types
    In MongoDB, data is stored in BSON format, which supports various data types.
    Knowing these types is important for effective schema design and query performance.
0. countDocuments()
2. estimatedDocumentCount()
3. count()
 How to Use It
Example:
Output
 Performance Note
            Using full can slow down your database, so use it carefully on large
            collections.
o   What is a Cursor?
       A cursor is like a pointer that allows you to go through the results of a
          query one document at a time.
       In MongoDB, a cursor acts as a pointer to the documents in a
          collection, and it allows you to retrieve documents one at a time.
       When you ask MongoDB for documents, it gives you a cursor to help
          you retrieve them.
       Creating a Cursor: When you run a query (like finding documents),
          MongoDB automatically creates a cursor.
           const cursor = db.collection('myCollection').find();
           Iterating Through Documents: You can loop through the results using
            the forEach method:
           cursor.forEach((doc) => {
             console.log(doc); // This prints each document to the
            console
           });
           Cursor Methods
           const cursor = db
             .collection('myCollection')
             .find({ age: { $gt: 25 } })
             .sort('name', 1)
             .limit(10)
             .skip(20)
             .project({ name: 1, _id: 0 });
 Closing Cursor
    In MongoDB, you use collections to store documents. To add data, you can
    use two main methods: insertOne() and insertMany().
            db.collection.insertMany([
                { name: 'Ai', age: 20 },
                { name: 'Ash', age: 21 },
                { name: 'Messi', age: 35 }
            ]);
o find()
    The find() method is used to search for documents within a collection. You
    can filter, sort, and limit the results based on your needs.
 2. Query Filters
 3. Logical Operators
             Use logical operators like $and, $or, and $not for complex queries.
           db.users.find({ $and: [{ age: 25 }, { first_name:
           'John' }] }); // Finds users who are 25 and named John
 4. Projection
 5. Sorting
    The _id field is a unique identifier for each MongoDB document. Its default value is
    an ObjectId, which has the following structure:
Example of an ObjectId:
64d7f9e1d8347a12cfc1b032
 OPERATORS
       o    Comparison Operators
               $eq (Equal)
                   Checks if two values are equal; returns true if they are, otherwise
                   false.
           Syntax
        { field: { $nin: [<value1>, <value2>, ..., <valueN>]
          } }
           Example
            [
              { _id: 1, title:      'The Silent Patient', genre:
            'Mystery' },
              { _id: 2, title:      'Dune', genre: 'Sci-Fi' },
              { _id: 3, title:      'Educated', genre:
            'Biography' },
              { _id: 4, title:      'The Alchemist', genre:
            'Adventure' },
              { _id: 5, title:      'The Great Gatsby' }
            ]
Summary
 $in
          Syntax
        { field: { $in: [<value1>, <value2>, ...] } }
          Example
           [
             { _id: 1, title:      'MongoDB', tags: ['database',
           'NoSQL'] },
             { _id: 2, title:      'Node.js', tags: ['javascript',
           'runtime'] },
             { _id: 3, title:      'React', tags: ['NoSQL',
           'javascript'] },
             { _id: 4, title:      'React', tags: ['SQL',
           'React'] },
             { _id: 5, title:      'React', tags: ['React',
           'MySQL'] },
           ]
                   Result:
                   [
                     { _id: 1, title: 'MongoDB', tags:
                    ['database', 'NoSQL'] },
                     { _id: 2, title: 'Node.js', tags:
                    ['javascript', 'runtime'] },
                     { _id: 3, title: 'React', tags: ['NoSQL',
                    'javascript'] }
                   ]
                  Summary
                  The $in operator lets you check if a field’s value exists within
                  a specified list of values, which is useful for filtering multiple
                  possible matches.
o   Logical Operators
          $and
                 Syntax:
               { $and: [{ condition1 }, { condition2 }, ... ] }
                 Example: Find orders with a price greater than 1 and quantity
                  less than 10:
               db.orders.find({ $and: [{ price: { $gt: 1 } },
                 { quantity: { $lt: 10 } }] });
                     Results:
               { "_id": 3, "item": "orange", "price": 2,
                 "quantity": 5 }
Note
You can also achieve the same result without using $and:
 $or
           The $or operator allows you to query multiple conditions and returns
           documents that satisfy any of the specified conditions.
                 Syntax:
               {
                 $or: [
                   { condition1 },
                   { condition2 },
                   // ...,
                   { conditionN }
                 ]
               }
                 Example: Find products where the category is "Fruits" or the
                  price is less than or equal to 15:
               db.products.find({
                 $or: [
                   { category: 'Fruits' },
                   { price: { $lte: 15 } }
                 ]
               });
                     Results:
                     [
                        { _id: 1, category: 'Fruits', price: 20 },
                        { _id: 2, category: 'Fruits', price: 30 },
                        { _id: 3, category: 'Vegetables', price: 10
                     },
                        { _id: 4, category: 'Vegetables', price: 15
                     }
                    ]
                    To find documents where the category is "Fruits" and
                     the price is either less than 20 or greater than 25:
        db.products.find({
          $and: [
            { category: 'Fruits' },
            {
              $or: [
                { price: { $lt: 20 } },
                { price: { $gt: 25 } }
              ]
            }
          ]
        });
              Results:
              [{ _id: 2, category: 'Fruits', price: 30 }]
   $not
          Syntax:
        {
          field: { $not: { <operator-expression> } }
        }
          Examples
                 Syntax
               { $nor: [ { <condition1> },
                 { <condition2> }, ... ] }
                 Example
                  [
                    { _id: 1, name: 'Alice', age: 30, subjects:
                  ['math', 'science'] },
                    { _id: 2, name: 'Bob', age: 25, subjects:
                  ['history'] },
                    { _id: 3, name: 'Cathy', age: 35, subjects:
                  ['math', 'history'] },
                    { _id: 4, name: 'David', age: 28, subjects:
                  ['science'] },
                  ]
Query
Find students who are not older than 30 and not studying math:
                  db.students.find({
                    $nor: [{ age: { $gt: 30 } }, { subjects:
                  'math' }],
                  });
                          Result:
                          [
                            { _id: 2,    name: 'Bob', age: 25, subjects:
                           ['history']    },
                            { _id: 4,    name: 'David', age: 28, subjects:
                           ['science']    }
                          ]
o   Array Operators
          $all
                 Syntax
               {
                 <field>: {
                   $all: [<value1>, <value2>, ..., <valueN>]
                 }
               }
                 Example
To find all movies with both the "action" and "sci-fi" tags:
                   Result:
                   [
                     { _id: 1, title: "The Matrix", tags:
                    ["action", "sci-fi", "cyberpunk"] },
                     { _id: 2, title: "Inception", tags:
                    ["action", "thriller", "sci-fi"] }
                   ]
Summary
 $elemMatch
    The $elemMatch operator checks which object in the array meets the
    specified conditions in the query. dealing with arrays of objects
          Syntax
        {
           <field>: {
             $elemMatch: { <condition1>, <condition2>, ...,
           <conditionN> }
           }
        }
          Example
           [
  { _id: 1, student:      "Mary", grades: [{ subject:
"Math", score: 80 },      { subject: "English", score:
75 }] },
  { _id: 2, student:      "Tom", grades: [{ subject:
"Math", score: 90 },      { subject: "English", score:
80 }] },
  { _id: 3, student:      "John", grades: [{ subject:
"Math", score: 85 },      { subject: "English", score:
65 }] },
  { _id: 4, student:      "Lucy", grades: [{ subject:
"Math", score: 70 },      { subject: "English", score:
85 }] }
]
Query
db.courseRecords.find({
  grades: {
    $elemMatch: {
      subject: "Math",
      score: { $gte: 80 }
    }
  }
});
Explanation of Query
        [
          { _id: 1, student: "Mary", grades:
        [{ subject: "Math", score: 80 }, { subject:
        "English", score: 75 }] },
          { _id: 2, student: "Tom", grades:
        [{ subject: "Math", score: 90 }, { subject:
        "English", score: 80 }] },
          { _id: 3, student: "John", grades:
        [{ subject: "Math", score: 85 }, { subject:
        "English", score: 65 }] }
        ]
                     Result Explanation
           Syntax
        { "<array_field>": { "$size": <number_of_elements> }
          }
              <array_field>: The name of the array field you want
                     to check.
                    <number_of_elements>: The exact number of
                  elements you want to match.
           Example
            [
              { "_id": 1, "name": "Shirt", "colors": ["red",
            "blue", "green"] },
              { "_id": 2, "name": "Pants", "colors": ["black",
            "white", "grey", "blue", "red"] },
              { "_id": 3, "name": "Hat", "colors": ["yellow"] }
            ]
            To find all products that have exactly 5 colors, you would use
            the following query:
 Result
                     [
                       { "_id": 2, "name": "Pants", "colors":
                     ["black", "white", "grey", "blue", "red"] }
                     ]
                     Important Notes
                                   The $size operator matches documents that
                                    have an exact number of elements in the
                                    specified array field.
                                   For more flexible array length comparisons
                                    (e.g., greater than or less than), you might need
                                    to use $expr along with $size in the
                                    aggregation framework.
                                   The $size operator does not require an
                                    additional index for efficiency; it can utilize
                                    existing indexes on the array field.
o   Element Operators
          $exists
                 Syntax
               { "field": { "$exists": <boolean> } }
                 Example
               [
                  { "_id": 1, "title": "MongoDB Basics", "author":
                  "John Doe" },
                  { "_id": 2, "title": "Advanced MongoDB",
                  "published": 2022 },
                  { "_id": 3, "title": "JavaScript", "author": "Jan
                  Smit", "edition": null }
               ]
    The $type operator is used to filter documents based on the data type
    of a specified field. It allows you to query for documents that have
    fields of a certain BSON data type.
           Syntax
        {
          fieldName: {
            $type: dataType
          }
        }
              fieldName: The name of the field you want to check.
              dataType: The BSON data type or its corresponding
                 alias.
           Common BSON Data Types and Aliases
                Type            Alias
            Double        1 or "double"
            String        2 or "string"
            Object        3 or "object"
            Array         4 or "array"
            Binary        5 or "binData"
            ObjectId      7 or "objectId"
            Boolean       8 or "bool"
            Date          9 or "date"
            Null          10 or "null"
            Int32         16 or "int"
            Int64         18 or "long"
            Decimal128    19 or "decimal"
 Example
            [
              { "_id": 1, "name": "Laptop", "price": 999.99,
            "inStock": true },
              { "_id": 2, "name": "Smartphone", "price":
            599.99, "inStock": true },
              { "_id": 3, "name": "Tablet", "price": "300",
            "inStock": "yes" }, // price is a string
              { "_id": 4, "name": "Headphones", "price": null,
            "inStock": false },
  { "_id": 5, "name": "Monitor", "price": 250.00,
"inStock": true }
]
 Result:
               [
                 { "_id": 1, "name": "Laptop",
               "price": 999.99, "inStock": true },
                 { "_id": 2, "name": "Smartphone",
               "price": 599.99, "inStock": true },
                 { "_id": 5, "name": "Monitor",
               "price": 250.00, "inStock": true }
               ]
 Result:
               [
                 { "_id": 3, "name": "Tablet",
               "price": "300", "inStock": "yes" }
               ]
 Result:
                                      [
                                        { "_id": 4, "name": "Headphones",
                                      "price": null, "inStock": false }
                                      ]
Summary
                  Syntax:
                 db.collection.find({
                    $expr: { $gt: ["$field1", "$field2"] }
                 });
                   Example Find documents where field1 is greater than field2
                 [
                    { "_id": 1, "field1": 10, "field2": 5 },
                    { "_id": 2, "field1": 3, "field2": 8 },
                    { "_id": 3, "field1": 15, "field2": 15 }
                 ]
Query:
                   db.collection.find({
                     $expr: { $gt: ["$field1", "$field2"] }
                   });
                           Result:
                           [
                               { "_id": 1, "field1": 10, "field2": 5 }
                           ]
                     Conclusion
 $regex
 Syntax
0. /al/:
                         Result
                         [
                             { "_id": 1, "name": "Alice Johnson" }
                         ]
                  Case-Insensitive Search:
                  db.users.find({ name: { $regex: 'alice',
                   $options: 'i' } });
                         Result
                         [
                             { "_id": 1, "name": "Alice Johnson" }
                         ]
                         Result
                         []
          Summary
          The $regex operator allows you to search for patterns in text
           fields, making it a useful tool for flexible querying in
           MongoDB.
 $jsonSchema
        Syntax:
        db.collection.find({
          $jsonSchema: {
            bsonType: "object",
            required: ["name", "age"],
            properties: {
              name: { bsonType: "string" },
              age: { bsonType: "int", minimum: 18 }
            }
          }
        });
        Example
        [
          { "_id": 1, "name": "Alice", "age": 30 },
          { "_id": 2, "name": "Bob", "age": 17 },
          { "_id": 3, "name": "Charlie", "age": 22 }
        ]
Query
                  Result:
                  [
                      { "_id": 1, "name": "Alice", "age": 30 },
                      { "_id": 3, "name": "Charlie", "age": 22 }
                  ]
Conclusion
 $mod
        Syntax:
        db.collection.find({
          field: { $mod: [divisor, remainder] }
        });
        Example
        [
          { "_id": 1, "number": 10 },
          { "_id": 2, "number": 15 },
          { "_id": 3, "number": 20 }
        ]
Query
                  Result:
                  [
                      { "_id": 1, "number": 10 },
                      { "_id": 3, "number": 20 }
                  ]
Conclusion
 $text
        Syntax:
        db.collection.find({
           $text: { $search: "some text" }
        });
        Example
        [
           { "_id": 1, "content": "Learn MongoDB basics" },
           { "_id": 2, "content": "Advanced MongoDB
           techniques" },
           { "_id": 3, "content": "JavaScript programming" }
        ]
Query
                  Result:
                  [
                    { "_id": 1, "content": "Learn MongoDB
                   basics" },
                    { "_id": 2, "content": "Advanced MongoDB
                   techniques" }
                  ]
               
                      Conclusion
 $where
                     Syntax:
                 db.collection.find({
                   $where: "this.field > value"
                 });
                     Example
                 [
                      { "_id": 1, "value": 10 },
                      { "_id": 2, "value": 20 },
                      { "_id": 3, "value": 30 }
                 ]
Query
                            Result:
                            [
                                { "_id": 2, "value": 20 },
                                { "_id": 3, "value": 30 }
                            ]
Conclusion
o   Update Operators
       $set: Sets the value of a field in a document.
              Example Document:
               { "_id": 1, "name": "Alice", "age": 25 }
               Query:
               db.users.updateOne(
                  { _id: 1 },
                  { $set: { age: 30 }}
               );
               Result:
               { "_id": 1, "name": "Alice", "age": 30 }
          $unset: Removes a field from a document.
        Example Document:
        { "_id": 1, "name": "Alice", "email":
           "alice@example.com" }
        Query:
        db.users.updateOne(
           { _id: 1 },
           { $unset: { email: "" }}
        );
        Result:
        { "_id": 1, "name": "Alice" }
   $inc: Increments the value of a field by a specified amount.
        Example Document:
        { "_id": 1, "name": "Alice", "age": 30 }
        Query:
        db.users.updateOne(
           { _id: 1 },
           { $inc: { age: 1 }}
        );
        Result:
        { "_id": 1, "name": "Alice", "age": 31 }
   **$push**: Adds an element to an array field.
        Example Document:
        { "_id": 1, "name": "Alice", "hobbies":
           ["Reading"] }
        Query:
        db.users.updateOne(
           { _id: 1 },
           { $push: { hobbies: "Cooking" }}
        );
        Result:
        { "_id": 1, "name": "Alice", "hobbies": ["Reading",
           "Cooking"] }
   $addToSet: Adds a value to an array only if it doesn't already exist in
    the array.
         Example Document:
        {
          "_id": 1,
          "name": "Alice",
          "hobbies": ["Reading", "Cycling", "Swimming"]
        }
        Query:
        Now, if we try to add "Swimming" again using $addToSet,
           we would run:
        db.users.updateOne(
           { _id: 1 },                                  // Find the
           document with _id equal to 1
           { $addToSet: { hobbies: "Swimming" }} // Try to
           add "Swimming" to the hobbies array
        );
        Result:
        {
           "_id": 1,
           "name": "Alice",
           "hobbies": ["Reading", "Cycling", "Swimming"]
        }
   $pop: Removes the first or last element of an array.
               Example Document:
               { "_id": 1, "name": "Alice", "hobbies": ["Reading",
                  "Cooking"] }
               Query:
               db.users.updateOne(
                  { _id: 1 },
                  { $pop: { hobbies: 1 }}
               );
               Result:
               { "_id": 1, "name": "Alice", "hobbies":
                  ["Reading"] }
          $pull: Removes all instances of a value from an array.
               Example Document:
               { "_id": 1, "name": "Alice", "hobbies": ["Reading",
                  "Cooking"] }
               Query:
               db.users.updateOne(
                  { _id: 1 },
                  { $pull: { hobbies: "Reading" }}
               );
               Result:
               { "_id": 1, "name": "Alice", "hobbies":
                  ["Cooking"] }
          $rename: Renames a field.
               Example Document:
               { "_id": 1, "name": "Alice", "age": 25 }
               Query:
               db.users.updateOne(
                  { _id: 1 },
                  { $rename: { name: "fullName" }}
               );
               Result:
               { "_id": 1, "fullName": "Alice", "age": 25 }
o   Projection Operators
          $project
               Syntax
               { $project: { field1: <value>, field2:
                 <value>, ... } }
                     field1, field2: Names of the fields to include   (1) or
                        exclude (0).
                 Example
                  {
                      "_id": 1,
                      "name": "John Doe",
                      "age": 30,
                      "email": "john@example.com"
                  }
           Query:
           db.users.aggregate([
             {
               $project: {
                 name: 1,
                 email: 0 // Exclude email
               }
             }
           ]);
                    Result
                    {
                        "_id": 1,
                        "name": "John Doe"
                    }
 $include
        Syntax
        { field: 1 }
              field: The name of the field to include.
              1: Indicates that the field should be included   in the
                     results.
 Example
           [
               {
                    "title": "The Catcher in the Rye",
                    "author": "J.D. Salinger",
                    "year": 1951,
                    "genre": "Literary fiction"
               },
               {
                    "title": "To Kill a Mockingbird",
                    "author": "Harper Lee",
                    "year": 1960,
                    "genre": "Southern Gothic"
               },
               {
                    "title": "Of Mice and Men",
                    "author": "John Steinbeck",
                    "year": 1937,
                    "genre": "Novella"
               }
           ]
Query:
                    Result
                    [
                        {
                            "title": "The Catcher in the Rye",
                            "author": "J.D. Salinger"
                        },
                        {
                            "title": "To Kill a Mockingbird",
                            "author": "Harper Lee"
                        },
                        {
                            "title": "Of Mice and Men",
                            "author": "John Steinbeck"
                        }
                    ]
Note
        Syntax
        {
          $project: {
            field1: 0,
            field2: 0,
            ...
          }
        }
        Example
           Suppose we have a collection called students with the
           following documents:
           [
             { "_id": 1, "name": "John Doe", "age": 20,
           "course": "Software Engineering" },
             { "_id": 2, "name": "Jane Smith", "age": 22,
           "course": "Computer Science" },
             { "_id": 3, "name": "Richard Roe", "age": 21,
           "course": "Information Technology" }
           ]
           If you want to fetch all the students but exclude the age field
           from the result, you can use the following command:
           db.students.aggregate([
             {
               $project: {
                 age: 0 // Exclude the age field
               }
             }
           ]);
 Result
                    [
                      { "_id": 1, "name": "John Doe", "course":
                    "Software Engineering" },
                      { "_id": 2, "name": "Jane Smith", "course":
                    "Computer Science" },
                      { "_id": 3, "name": "Richard Roe",
                    "course": "Information Technology" }
                    ]
Important Note
 $slice
          Syntax
       0. Limit number of elements:
       1. { field: { $slice: <number> } }
       2. Limit from a specific position:
       3. { field: { $slice: [<skip>, <limit>] } }
   Examples
Document:
           {
             "_id": 1,
             "title": "My First Post",
             "tags": ["mongodb", "database", "nosql",
           "backend"]
           }
Query:
                  Result:
                  {
                    "_id": 1,
                    "tags": ["mongodb", "database",
                   "nosql"]
                  }
       
Document:
           {
             "_id": 2,
             "title": "My Second Post",
             "tags": ["mongodb", "database", "nosql",
           "backend", "development", "coding"]
           }
Query:
                  Result:
                  {
                      "_id": 2,
                      "tags": ["development", "coding"]
                  }
    Conclusion
                     The $slice operator is a simple way to limit the number of
                     array items returned in MongoDB queries.
    A bulk write operation allows you to perform multiple write operations (insert,
    update, replace, or delete) in a single command for better performance and
    reduced network overhead.
          Syntax:
          db.collection.bulkWrite([
              { insertOne: { document: { /* document fields
           */ } } },
              { updateOne: { filter: { /* filter criteria */ },
           update: { /* update fields */ } } },
              { deleteOne: { filter: { /* filter criteria */ } } },
              // Additional operations...
          ])
          Example:
Collection: products
           [
                   { "_id": 1, "name": "Laptop", "price": 1200 },
                   { "_id": 2, "name": "Phone", "price": 800 },
                   { "_id": 3, "name": "Tablet", "price": 400 }
           ]
           Summary:
           The bulk write operation efficiently performs multiple write operations
           in a single call, improving performance and reducing the number of
           network requests.
o Accumulator Operators
Query:
                  db.transactions.aggregate([
                      { $group: { _id: "$category", totalAmount:
                  { $sum: "$amount" } } }
                  ])
                          Result:
                          [
                              { "_id": "Stationery", "totalAmount":
                           22 },
                              { "_id": "Fruit", "totalAmount": 1 }
                          ]
          $avg: Calculates the average of numeric values in a group.
               Syntax: { $avg: "<field>" }
               Example Collection: sales
               [
                    { "_id": 1, "product": "Laptop", "price": 1200,
                  "category": "Electronics" },
                    { "_id": 2, "product": "Phone", "price": 800,
                  "category": "Electronics" },
                    { "_id": 3, "product": "Tablet", "price": 600,
                  "category": "Electronics" }
               ]
Query:
                  db.sales.aggregate([
                      { $group: { _id: "$category", averagePrice:
                  { $avg: "$price" } } }
                  ])
                     Result:
                     [
                         { "_id": "Electronics", "averagePrice":
                      866.67 }
                     ]
   $min: Finds the minimum value in a group.
        Syntax: { $min: "<field>" }
        Example Collection: grades
        [
             { "_id": 1, "student": "Alice", "score": 85,
           "subject": "Math" },
             { "_id": 2, "student": "Bob", "score": 75,
           "subject": "Math" },
             { "_id": 3, "student": "Charlie", "score": 90,
           "subject": "Math" }
        ]
Query:
             db.grades.aggregate([
                 { $group: { _id: "$subject", minScore: { $min:
             "$score" } } }
             ])
                     Result:
                     [
                         { "_id": "Math", "minScore": 75 }
                     ]
   $max: Finds the maximum value in a group.
        Syntax: { $max: "<field>" }
        Example Collection: products
        [
             { "_id": 1, "name": "TV", "price": 500 },
             { "_id": 2, "name": "Laptop", "price": 1200 },
             { "_id": 3, "name": "Phone", "price": 800 }
        ]
Query:
             db.products.aggregate([
                 { $group: { _id: null, maxPrice: { $max:
             "$price" } } }
             ])
                     Result:
                     [
                         { "_id": null, "maxPrice": 1200 }
                     ]
   $first:Returns the first value in a group based on the order of
    documents.
        Syntax: { $first: "<field>" }
        Example Collection: orders
        [
               { "_id": 1, "customer": "Alice", "amount": 200,
             "date": "2024-01-01" },
               { "_id": 2, "customer": "Bob", "amount": 150,
             "date": "2024-02-01" },
               { "_id": 3, "customer": "Charlie", "amount":
             300, "date": "2024-03-01" }
        ]
Query:
             db.orders.aggregate([
                 { $group: { _id: null, firstOrder: { $first:
             "$customer" } } }
             ])
                     Result:
                     [
                         { "_id": null, "firstOrder": "Alice" }
                     ]
   $last:Returns the last value in a group based on the order of
    documents.
        Syntax: { $last: "<field>" }
        Example Collection: employees
        [
               { "_id": 1, "name": "Alice", "department": "HR",
             "joined": "2023-01-01" },
               { "_id": 2, "name": "Bob", "department": "HR",
             "joined": "2023-02-01" },
               { "_id": 3, "name": "Charlie", "department":
             "HR", "joined": "2023-03-01" }
        ]
Query:
             db.employees.aggregate([
                 { $group: { _id: "$department", lastJoined:
             { $last: "$name" } } }
             ])
                     Result:
                     [
                         { "_id": "HR", "lastJoined": "Charlie" }
                     ]
   $push:   Creates an array with all values from a specified field in a
    group.
        Syntax: { $push: "<field>" }
        Example Collection: inventory
        [
             { "_id": 1, "product": "Apple", "category":
           "Fruit" },
             { "_id": 2, "product": "Orange", "category":
           "Fruit" },
             { "_id": 3, "product": "Banana", "category":
           "Fruit" }
        ]
             Query:
                     db.inventory.aggregate([
                         { $group: { _id: "$category", allProducts:
                     { $push: "$product" } } }
                     ])
                             Result:
                             [
                                 { "_id": "Fruit", "allProducts":
                              ["Apple", "Orange", "Banana"] }
                             ]
          $addToSet:       Creates an array of unique values from a specified field in
           a group.
                Syntax: { $addToSet: "<field>" }
                Example Collection: purchases
                [
                       { "_id": 1, "product": "Apple", "category":
                     "Fruit" },
                       { "_id": 2, "product": "Apple", "category":
                     "Fruit" },
                       { "_id": 3, "product": "Banana", "category":
                     "Fruit" }
                ]
Query:
                     db.purchases.aggregate([
                         { $group: { _id: "$category", uniqueProducts: {
                     $addToSet: "$product" } } }
                     ])
                             Result:
                             [
                                 { "_id": "Fruit", "uniqueProducts":
                              ["Apple", "Banana"] }
                             ]
o   Upsert Option
          Syntax
          db.collection.updateOne(
              { filterCriteria },
              { updateOperations },
              { upsert: true }
          )
          Example
           [
                   { "_id": 1, "name": "Laptop", "price": 1200 }
           ]
                 If we try to update a document with a filter that doesn’t match any
                 existing documents, upsert will insert a new document.
                      Query:
                      db.products.updateOne(
                          { name: "Phone" },
                          { $set: { price: 800 } },
                          { upsert: true }
                      )
                      Result: Since no document with name: "Phone"        exists,
                          MongoDB inserts a new document:
                      { "_id": ObjectId(...), "name": "Phone", "price":
                        800 }
Summary
                 The upsert option is useful when you want to either update existing
                 documents or insert a new one if no matches are found in the
                 collection.
                Syntax
                { $match: { <query> } }
 Example
                 [
                   { "_id": 1,    "firstName": "John", "age": 25,
                 "department":    "HR" },
                   { "_id": 2,    "firstName": "Jane", "age": 35,
                 "department":    "Finance" },
                   { "_id": 3,    "firstName": "Mike", "age": 28,
                 "department":    "HR" }
                 ]
Query:
                 db.employees.aggregate([
                    { $match: { age: { $gt: 30 } } }
                 ])
                 Result
                 [
                    { "_id": 2, "firstName": "Jane", "age": 35,
                    "department": "Finance" }
                 ]
This result shows only the employee who is older than 30.
          Syntax
          {
              $group: {
                _id: <expression>,
                <field1>: { <accumulator1>: <expression1> },
                ...
              }
          }
                _id: The field or expression used to group the documents.
                <field1>: The name of the new field in the result that will hold
                 computed values.
               <accumulator1>: An accumulator operator (e.g., $sum, $avg,
                 $max, $min) that defines the calculation to perform.
               <expression1>: The field or expression to which the
                 accumulator applies.
          Example
           db.orders.aggregate([
              {
                $group: {
                  _id: "$customer_id",
                  total_spent: { $sum: "$amount" }
                }
              }
           ])
                 Result
                 [
                   { "_id": "C1", "total_spent": 200 },
                   { "_id": "C2", "total_spent": 200 },
                   { "_id": "C3", "total_spent": 200 }
                 ]
    The $sort operator in MongoDB is used to sort documents that pass through
    the aggregation pipeline based on specified field(s) in either ascending or
    descending order.
          Syntax
          { $sort: { field1: <sort order>, field2: <sort
           order>, ... } }
               field1, field2: The fields by which you want to sort          the
                 documents.
                <sort order>: Use 1 for ascending order and 1 for descending
                 order.
          Examples
           [
               { "_id": 1, "name": "Alice", "age": 22 },
               { "_id": 2, "name": "Bob", "age": 25 },
               { "_id": 3, "name": "Charlie", "age": 20 }
           ]
                            Result:
                            [
                                { "_id": 3, "name": "Charlie", "age": 20 },
                                { "_id": 1, "name": "Alice", "age": 22 },
                                { "_id": 2, "name": "Bob", "age": 25 }
                            ]
                     2: Sorting by Age in Descending Order
                            Result:
                           [
                               { "_id": 2, "name": "Bob", "age": 25 },
                               { "_id": 1, "name": "Alice", "age": 22 },
                               { "_id": 3, "name": "Charlie", "age": 20 }
                           ]
                   3: Sorting by Multiple Fields
                           Result:
                           [
                               { "_id": 2, "name": "Bob", "age": 25 },
                               { "_id": 1, "name": "Alice", "age": 22 },
                               { "_id": 3, "name": "Charlie", "age": 20 }
                           ]
Important Note
          Syntax
          { $project: { field1: <value>, field2: <value>, ... } }
               field1, field2: Names of the fields to include (1) or exclude (0).
          Example
           {
               "_id": 1,
               "name": "John Doe",
               "age": 30,
               "email": "john@example.com"
           }
Query:
           db.users.aggregate([
                {
                    $project: {
                      name: 1,
                      email: 0 // Exclude email
                    }
              }
            ]);
                  Result
                  {
                    "_id": 1,
                    "name": "John Doe"
                  }
                      This query returns documents that only include the name field
                      and exclude the email field.
           Syntax
           { $skip: <number> }
                <number>: The         number of documents to skip.
           Example
            [
                {   "_id":   1,   "name":   "John", "age": 28 },
                {   "_id":   2,   "name":   "Jane", "age": 32 },
                {   "_id":   3,   "name":   "Bob", "age": 25 },
                {   "_id":   4,   "name":   "Alice", "age": 30 },
                {   "_id":   5,   "name":   "Charlie", "age": 27 },
                {   "_id":   6,   "name":   "Diana", "age": 29 }
            ]
            db.employees.aggregate([
               { $skip: 3 }
            ])
                  Result:
                  [
                    { "_id": 4, "name": "Alice", "age": 30 },
                    { "_id": 5, "name": "Charlie", "age": 27 },
                    { "_id": 6, "name": "Diana", "age": 29 }
                  ]
            Important Notes
                Order Matters: The $skip operator does not guarantee the
                 order of documents passed through it, so it's recommended to
                 use $sort before $skip if the order is important.
              Performance Consideration: For better performance, consider
                 combining $skip with additional filters and placing it later in
                 the aggregation pipeline.
o   $limit Limits result count.
    The $limit operator restricts the number of documents that are passed to the
    next stage in the aggregation pipeline. It is particularly useful for debugging
    and controlling the output of queries.
          Syntax
          { $limit: <number> }
               <number>: The maximum             number of documents to return.
          Example
           [
               {    "_id":   1,   "name":   "John", "age": 28 },
               {    "_id":   2,   "name":   "Jane", "age": 32 },
               {    "_id":   3,   "name":   "Bob", "age": 25 },
               {    "_id":   4,   "name":   "Alice", "age": 30 },
               {    "_id":   5,   "name":   "Charlie", "age": 27 },
               {    "_id":   6,   "name":   "Diana", "age": 29 }
           ]
           db.employees.aggregate([
              { $limit: 3 }
           ])
                 Result:
                 [
                   { "_id": 1, "name": "John", "age": 28 },
                   { "_id": 2, "name": "Jane", "age": 32 },
                   { "_id": 3, "name": "Bob", "age": 25 }
                 ]
Important Notes
 Syntax
{ $sum: <expression> }
 Example
       [
           { "_id": 1, "total": 50 },
           { "_id": 2, "total": 100 },
           { "_id": 3, "total": 150 }
       ]
Objective
       You want to calculate the total sum of the total field across all
       documents in the orders collection.
       Aggregation Query
       db.orders.aggregate([
         {
           $group: {
             _id: null, // No specific grouping, we want the
       total for all documents
             totalSum: { $sum: "$total" } // Sum the 'total'
       field
           }
         }
       ]);
 Result
                [
                    {
                        "_id": null,
                        "totalSum": 300
                    }
                ]
                Explanation
                          $group:  Combines the documents into a single output
                           document.
                          totalSum: The new field in the output that contains the
                           sum of the total field from all documents.
                          $sum: "$total": Calculates the sum of the total
                           field.
    When you use the $unwind operator in MongoDB on an array that contains
    multiple objects, it will return each object in the array as a separate document.
    This allows you to work with each object individually, which is useful for
    analysis or manipulation of the data.
          Syntax
          {
              $unwind: {
                path: "<arrayField>",
                includeArrayIndex: "<string>", // Optional
                preserveNullAndEmptyArrays: <boolean> // Optional
              }
          }
                path: The field path of the array you want to unwind (prefixed
                 with $).
               includeArrayIndex: (Optional) Adds the index of the array
                 element.
               preserveNullAndEmptyArrays: (Optional) If true, includes
                 documents with no array.
          Example
           {
               "_id": 1,
               "item": "itemA",
               "orders": [
                 { "quantity": 2, "unitPrice": 10 },
                 { "quantity": 3, "unitPrice": 20 }
               ]
           }
Using $unwind:
           db.sales.aggregate([
              { $unwind: { path: "$orders" } }
           ])
                 Result:
                 [
                    { "_id": 1, "item": "itemA",        "orders":
                    { "quantity": 2, "unitPrice":        10 } },
                    { "_id": 1, "item": "itemA",        "orders":
                    { "quantity": 3, "unitPrice":        20 } }
                 ]
    The $lookup operator is used to perform a left outer join between two
    collections in MongoDB, allowing you to combine documents from one
    collection with documents from another based on a shared field.
          Syntax
          {
            "$lookup": {
              "from": "<collection_name>",
              "localField": "<field_from_input_documents>",
              "foreignField":
           "<field_from_documents_of_the_from_collection>",
              "as": "<output_array_field>"
            }
          }
Parameters
1. orders Collection
[
    { "orderId": 1, "productId": "A", "quantity": 2 },
    { "orderId": 2, "productId": "B", "quantity": 3 }
]
2. products Collection
[
  { "productId": "A", "productName": "Widget", "price":
10 },
  { "productId": "B", "productName": "Gadget", "price":
20 }
]
Aggregation Query
javascript
Copy code
db.orders.aggregate([
  {
     $lookup: {
       from: 'products',
       localField: 'productId',
       foreignField: 'productId',
       as: 'productDetails'
     }
  },
  {
     $unwind: '$productDetails' // Flatten the array of
product details
  },
  {
     $project: {
       orderId: 1,
       totalAmount: {
         $multiply: ['$quantity', '$productDetails.price']
// Calculate total amount
       }
     }
  }
]);
 Result
Explanation
Conclusion
    The $bucket operator takes a set of documents and divides them into discrete
    groups, called buckets, based on a specified field. Each bucket can represent a
    range of values, and you can perform aggregate calculations on the documents
    in each bucket.
 Syntax
           {
             $bucket: {
               groupBy: <expression>,          // The field to group
           by (e.g., a number or date).
               boundaries: [ <boundary1>, <boundary2>, ... ], // An
           array of boundary values that define the ranges for the
           buckets.
               default: <defaultBucket>,       // (Optional) Name of
           the bucket for values outside the specified boundaries.
               output: {                       // An object defining
           what to return for each bucket.
                 <outputField1>: { <accumulator1>: <expression1> },
                 ...
               }
             }
           }
          Example
Imagine you have a collection called scores that contains students'
exam scores:
[
    {    "student":   "Alice", "score": 85 },
    {    "student":   "Bob", "score": 92 },
    {    "student":   "Charlie", "score": 75 },
    {    "student":   "David", "score": 65 },
    {    "student":   "Eve", "score": 89 },
    {    "student":   "Frank", "score": 55 }
]
Using $bucket
You want to group these scores into ranges (buckets) to see how many
students fall into each score range.
Aggregation Query
javascript
Copy code
db.scores.aggregate([
  {
    $bucket: {
      groupBy: "$score",                     // Group by
the 'score' field.
      boundaries: [0, 60, 75, 85, 100],     // Define the
boundaries for the buckets.
      default: "Other",                      // Optional:
Name for scores outside the defined ranges.
      output: {
        count: { $sum: 1 },                  // Count the
number of students in each bucket.
        totalScore: { $sum: "$score" }       // Sum the
scores in each bucket.
      }
    }
  }
]);
 Result
          [
            { "range": "[0, 60)", "count": 1, "totalScore":
          55 },   // 1 student with a score < 60
            { "range": "[60, 75)", "count": 1, "totalScore":
          65 },   // 1 student with a score between 60 and 75
            { "range": "[75, 85)", "count": 2, "totalScore":
          164 }, // 2 students with scores between 75 and 85
            { "range": "[85, 100)", "count": 2, "totalScore":
          177 } // 2 students with scores between 85 and 100
          ]
                    Explanation of the Result
Conclusion
           Syntax:
           { $out: "outputCollection" }
           Example:
            [
                { "_id": 1, "product":        "Laptop", "amount": 1200,
            "status": "completed" },
                { "_id": 2, "product":        "Phone", "amount": 800,
            "status": "completed" },
                { "_id": 3, "product":        "Tablet", "amount": 400,
            "status": "pending" },
                { "_id": 4, "product":        "Monitor", "amount": 300,
            "status": "completed" },
                { "_id": 5, "product":        "Keyboard", "amount": 150,
            "status": "completed" }
            ]
          Syntax:
          { $facet: { stage1: [ <pipeline1> ], stage2:
           [ <pipeline2> ] } }
          Example:
           [
               { "_id": 1, "product":           "Laptop", "amount": 1200,
           "status": "completed" },
               { "_id": 2, "product":           "Phone", "amount": 800,
           "status": "completed" },
               { "_id": 3, "product":           "Tablet", "amount": 400,
           "status": "pending" },
               { "_id": 4, "product":           "Monitor", "amount": 300,
           "status": "completed" },
               { "_id": 5, "product":           "Keyboard", "amount": 150,
           "status": "completed" }
           ]
    The $fill operator in MongoDB is used to fill in gaps in time series data
    during an aggregation operation. Specifically, it allows you to specify default
    values for fields when there are missing documents for certain time intervals
    in the output of an aggregation pipeline.
           Syntax
           {
               $fill: {
                 output: {
                   fieldName1: value1,
                   fieldName2: value2,
                   // ... additional fields as needed
                 }
               }
           }
       
           Example:
Aggregation Query:
            You want to get the average temperature for each day, filling missing
            days with a default temperature of 0.
            db.temperatureReadings.aggregate([
              {
                 $group: {
                   _id: { $dateTrunc: { date: "$date", unit:
            "day" } },
                   avgTemperature: { $avg: "$temperature" }
                 }
              },
              {
                 $fill: {
                   output: { avgTemperature: 0 }
                 }
              }
            ]);
 Result:
       0. Pipeline:
              A pipeline is a series of stages executed in order to process the data.
              Each stage transforms the data and passes it to the next stage.
              The output of the last stage is the final result of the pipeline.
       1. Stage:
              A stage is a single operation applied to the data.
              It can involve simple transformations or complex aggregations.
              Each stage has a specific purpose and is responsible for a single task.
       2. Operator:
              An operator is a special symbol used to perform specific operations on
                 the data.
              Operators can be mathematical, logical, or comparison-based.
Conclusion
    The aggregation framework in MongoDB is a powerful tool for data processing and
    analysis, allowing users to perform complex queries and calculations efficiently.
    Understanding the concepts of pipelines, stages, and operators is essential for
    leveraging this capability effectively.
This counts all documents in the collection where the status field is "active".
Summary:
    Single-purpose aggregation methods are used for tasks like counting, finding distinct
    values, or basic group operations. They are ideal when you need quick, simple results,
    without the need for the more extensive aggregation framework.
 ACID
                    Example: If two customers try to purchase the last item in stock at the
                    same time, isolation ensures that only one of them completes the
                    transaction to avoid double selling.
   Transactions in MongoDB
       o MongoDB generally follows the BASE principles for its consistency model,
          especially in the context of its replication and sharding features, where
          eventual consistency is prioritized for availability and scalability.
       o However, MongoDB transactions, starting from version 4.0, follow ACID
          principles for multi-document operations. This means MongoDB can support
          ACID transactions (Atomicity, Consistency, Isolation, Durability) when
          needed for complex operations like updates across multiple documents or
          collections.
   Journaling in MongoDB
    In MongoDB, journaling is a feature that helps protect your data. When you make
    changes to the database, MongoDB first records these changes in a "journal" before
    saving them. This journal acts like a backup, so if MongoDB unexpectedly shuts
    down, it can use the journal to recover and keep your data safe.
       0. Consistency: All nodes have the same data at the same time. Every read
          returns the most recent write.
       1. Availability: Every request gets a response, even if the data isn't up to date.
          The system is always operational.
       2. Partition Tolerance: The system continues to work despite network failures
          between nodes.
Key Points:
Conclusion:
    The CAP theorem helps developers understand the trade-offs in designing distributed
    systems, guiding decisions based on specific needs.
o malayalam
    Replica Sets are groups of MongoDB servers that maintain the same dataset. A
    replica set has:
       o    Primary Node: The main server where all write operations happen. It
            replicates data to secondary nodes.
       o  Secondary Nodes: Servers that replicate data from the primary. They can
          serve read requests if configured, and if the primary fails, one secondary
          becomes the new primary.
       o Arbiter: A member that does not hold data but helps with elections to decide
          which secondary becomes the primary during failover.
   Types of Replication
       o 1 . Master-Slave Replication (Old model, now deprecated)
               How it works: One server (master) handles all the writes, and other
                  servers (slaves) copy the data from the master.
               Problem: If the master goes down, no one can write to the database.
               Current Status: No longer used in recent MongoDB versions.
       o
                 How it works: MongoDB data is split into shards (parts), and each
                  shard is a replica set.
                 Features:
                       Used when you need to store huge amounts of data that can't fit
                          on a single server.
                       Each shard can handle reads and writes, and data is
                          automatically distributed across servers.
                 Current Status: Used for horizontal scaling when the database grows
                  too large for one replica set.
       o
    Summary
          Type                      Description                 Failover     Scalability
                     One master, one or more slaves (old
    Master-Slave                                               Manual      Limited
                     model)
                     Primary and secondary servers
    Replica Sets                                               Automatic Can scale reads
                     (current model)
                     Data is split across multiple replica                 Handles huge
    Sharded Clusters                                           Automatic
                     sets                                                  data
    Delayed Replica A secondary node has a delay for
                                                               Manual      No impact
    Sets             recovery
 Indexing
                 Type of Indexing
                      
                             0. Single Field Index (Default Index)
db.collection.createIndex({ name: 1 })
2. Compound Index
3. Multikey Index
db.collection.createIndex({ tags: 1 })
4. Text Index
5. Hashed Index
6. Geospatial Index
7. Wildcard Index
db.collection.createIndex({ "$**": 1 })
    db.logs.insertOne({
       message: "Temporary log",
       createdAt: new Date() // Current time
    });
    db.logs.createIndex(
       { "createdAt": 1 }, // Index on createdAt field
       { expireAfterSeconds: 30 } // Expire after 30 seconds
    );
o The trade-off
 Example of Trade-offs
What is a B-tree?
    A B-tree is a type of tree data structure used to organize and store data
    efficiently. It’s commonly used in databases and filesystems.
 Key Features:
                0.   Balanced: All leaf nodes (end points) are at the same level,
                     which keeps the tree balanced.
              1.  Multi-way Nodes: Each node can have multiple keys and
                  children, not just two like a regular binary tree.
             2. Sorted Data: Keys within each node are kept in sorted order,
                  making searches faster.
             3. Efficient Operations: B-trees allow for quick searching,
                  inserting, and deleting of keys.
          How It Works:
           css
           Copy code
                            [10, 20]
                       /        |     \\
                   /            |      \\
              [5]             [15]   [25, 30]
           B-trees are great for efficiently managing large amounts of sorted data,
           making them ideal for databases where quick access is essential.
o   Covered Query
        All the fields in the query are part of an index.
        All the fields returned in the query are in the same index
        Purpose: The primary benefit of a covered query is performance
          improvement. Since MongoDB can retrieve the requested data directly
          from the index, it avoids the overhead of fetching documents from the
          data store, making the query faster and using less I/O.
        Requirements for a Covered Query:
              0.   The query must only reference fields that are part of an index.
                      1.All fields in the projection (the fields you want to return) must
                        also be included in the index.
                     2. The _id field is implicitly included in every index.
                 Example
Then for second query of similar type it doesn’t race them again.
o GridFS
   Database scaling
       o Vertical Scaling (Scaling Up)
               What it Means: Increasing the capacity of a single MongoDB server
                  by adding more resources, like CPU, RAM, or storage.
               Benefits: Simple to implement, as you’re only working with one
                  server.
               Limitations: Limited by the maximum hardware capacity of that
                  single server, and costs can increase with higher specifications.
               Usage: Useful for small or medium-sized databases where the
                  workload can be handled by a single, more powerful server.
       o Horizontal Scaling (Scaling Out)
               What it Means: Adding more servers to distribute the workload,
                  especially for large databases or high traffic.
               Key Methods in MongoDB:
           MongoDB uses these techniques to grow with your data and user base,
           keeping the database fast and reliable.
                  Examples:
                       Enable Profiler for Slow Queries (queries slower than
                         100ms):
                       bb.setProfilingLevel(1, { slowms: 100 });
                       Enable Profiler for All Operations:
                       db.setProfilingLevel(2);
                       View Collected Data:
                       db.system.profile.find().sort({ ts: -1 });
       o    Syntax
       o    db.createColllection("cappedCollection", { capped: true, size:
            100 })
                Explanation
                      db.createCollection: This is the method used to create a
                          collection.
                         "cappedCollection": This is the name of the new capped
                          collection you want to create.
                       { capped: true, size: 100 }: This option specifies that the
                          collection should be capped, meaning it has a fixed size. In this
                          case, the size is set to 100 bytes.
       o    How to check the collection is capped or not
       o    // if the collection is capped it will return true else it will
            return false
       o    db.collectionName.isCapped();
   Clustered collection
    A clustered collection organizes data based on a cluster key, which helps store and
    retrieve related data more efficiently.
       0. Cluster Key:
               Documents are stored in a specific order based on this key. For
                 example, if you often query data by a user_id, setting user_id as the
                 cluster key will make those queries faster.
       1. Efficient Storage:
               Clustered collections use less storage for large datasets because they
                 are ordered, which helps reduce index size.
       2. Optimized Performance:
               Retrieving data by the cluster key is faster, which can improve
                 performance in large databases.
    Note: As of now, MongoDB doesn’t natively support clustered collections the same
    way as some relational databases do, but MongoDB’s indexing and sharding options
    offer similar advantages.
 WiredTiger
    Advantages of WiredTiger:
       o  Improved performance and storage efficiency for databases with high read and
          write demands.
      o Lower disk space usage thanks to compression.
      o Enhanced concurrency with document-level locking, making it ideal for
          workloads with multiple users or applications.
   Write Concern: & Read Concern:
      o Write Concern: MongoDB double-checks that data is saved.
      o Read Concern: MongoDB makes sure data is recent when you read it.
o Write Concern:
           Write concern is about making sure your data is saved safely when you add,
           change, or delete something.
           So, write concern is just how much you want MongoDB to double-check
           that your data is saved.
o Read Concern:
Read concern is about how fresh or updated the data is when you read it.
              0. Quick Read: You get the data fast, but it might not be the latest from
                 all servers.
              1. Confirmed Read: You get data only after MongoDB checks with
                 multiple servers. More accurate, but takes a bit longer.
 allowDiskUse
    The allowDiskUse option in MongoDB is like asking for permission to use disk
    space when an aggregation result takes more than the default memory limit of 100
    MB.
   Normalization
 Watch
    In MongoDB, watch allows you to see changes in the database as they happen. It's
    like keeping an eye on your data so you know when something is added, updated, or
    deleted, and you can react to it right away.
 Profiler
    Profiler helps you track and analyze the performance of your database by logging
    information about operations, like queries and updates. It shows which operations are
    slow, so you can identify and fix performance problems.
       o    How to Use:
              0. Enable Profiling:
               1. db.setProfilingLevel(1, { slowms: 100 });
       o    Find Slow Queries: Helps you see which queries are slow.
       o    Improve Performance: Lets you optimize slow operations for faster
            performance.
   Oplog
    In MongoDB, the Oplog (short for operation log) is a special capped collection that
    records all changes made to the data in the database. It is used primarily in replica
    sets to synchronize data across different members (nodes) of the replica set.