MongoDB Limit

Control query results and implement pagination with limit and skip

🎯 What is MongoDB Limit?

The limit() method in MongoDB restricts the number of documents returned by a query. Combined with skip(), it enables efficient pagination and result control. This is essential for performance optimization, especially when dealing with large datasets, as it prevents loading unnecessary data.


// Basic limit usage
db.users.find().limit(5)        // Return only first 5 documents

// Limit with skip for pagination
db.products.find()
    .skip(10)                    // Skip first 10 documents
    .limit(5)                    // Return next 5 documents

// Limit with sorting
db.posts.find().sort({ date: -1 }).limit(3)  // Latest 3 posts
                                    
Control
Result Size
Pagination
Support
Performance
Optimization

Limit and Skip Methods

🎯

limit()

Restrict number of results

db.users.find().limit(10)
⏭️

skip()

Skip specified number of documents

db.users.find().skip(20)
📄

Pagination

Combine skip and limit

db.users.find()
    .skip(20).limit(10)
🔢

With Sorting

Order results before limiting

db.posts.find()
    .sort({ date: -1 })
    .limit(5)

Basic Limit Operations

Learn how to control the number of documents returned by queries

// Sample data
db.products.insertMany([
    { _id: 1, name: "Laptop", price: 999, category: "electronics" },
    { _id: 2, name: "Phone", price: 599, category: "electronics" },
    { _id: 3, name: "Tablet", price: 399, category: "electronics" },
    { _id: 4, name: "Book", price: 19, category: "books" },
    { _id: 5, name: "Pen", price: 2, category: "stationery" },
    { _id: 6, name: "Notebook", price: 5, category: "stationery" },
    { _id: 7, name: "Mouse", price: 25, category: "electronics" },
    { _id: 8, name: "Keyboard", price: 75, category: "electronics" }
])

// Basic limit - get only first 3 documents
print("First 3 products:")
db.products.find().limit(3).forEach(printjson)

// Limit with filter - get first 2 electronics
print("\nFirst 2 electronics:")
db.products.find({ category: "electronics" }).limit(2).forEach(printjson)

// Limit with projection - get only names of first 4 products
print("\nFirst 4 product names:")
db.products.find({}, { name: 1, _id: 0 }).limit(4).forEach(printjson)

Skip and Pagination

Use skip() to implement pagination and navigate through large datasets

🔹 Basic Skip Operation

// Skip first 3 documents
print("Skip first 3 products:")
db.products.find().skip(3).forEach(printjson)

// Skip and limit together
print("\nSkip 2, limit 3 (products 3-5):")
db.products.find().skip(2).limit(3).forEach(printjson)

// Skip with filter
print("\nSkip first electronics item, get next 2:")
db.products.find({ category: "electronics" }).skip(1).limit(2).forEach(printjson)

🔹 Pagination Implementation

// Pagination function
function getPage(collection, pageNumber, pageSize, filter = {}) {
    var skip = (pageNumber - 1) * pageSize
    
    print(`Page ${pageNumber} (${pageSize} items per page):`)
    
    var results = db[collection].find(filter)
        .skip(skip)
        .limit(pageSize)
        .toArray()
    
    results.forEach(printjson)
    
    // Get total count for pagination info
    var totalCount = db[collection].countDocuments(filter)
    var totalPages = Math.ceil(totalCount / pageSize)
    
    print(`\nShowing page ${pageNumber} of ${totalPages} (${results.length} items)`)
    print(`Total items: ${totalCount}`)
    
    return {
        data: results,
        currentPage: pageNumber,
        totalPages: totalPages,
        totalItems: totalCount,
        hasNextPage: pageNumber < totalPages,
        hasPrevPage: pageNumber > 1
    }
}

// Usage examples
getPage("products", 1, 3)  // First page, 3 items
print("\n" + "=".repeat(50) + "\n")
getPage("products", 2, 3)  // Second page, 3 items
print("\n" + "=".repeat(50) + "\n")
getPage("products", 1, 2, { category: "electronics" })  // Electronics only

Limit with Sorting

Combine limit with sort to get top/bottom results

🔹 Top N Results

// Most expensive products (top 3)
print("Top 3 most expensive products:")
db.products.find().sort({ price: -1 }).limit(3).forEach(printjson)

// Cheapest products (bottom 3)
print("\nTop 3 cheapest products:")
db.products.find().sort({ price: 1 }).limit(3).forEach(printjson)

// Alphabetically first products
print("\nFirst 3 products alphabetically:")
db.products.find().sort({ name: 1 }).limit(3).forEach(printjson)

🔹 Category-wise Top Results

// Get top 2 products from each category
var categories = db.products.distinct("category")

categories.forEach(function(category) {
    print(`\nTop 2 products in ${category}:`)
    db.products.find({ category: category })
        .sort({ price: -1 })
        .limit(2)
        .forEach(printjson)
})

Advanced Limit Techniques

Advanced patterns and optimizations for limit operations

🔹 Random Sampling

// Get random documents using aggregation
print("3 random products:")
db.products.aggregate([
    { $sample: { size: 3 } }
]).forEach(printjson)

// Alternative: Skip random amount (less efficient for large collections)
function getRandomDocuments(collection, count) {
    var totalDocs = db[collection].countDocuments()
    var randomSkip = Math.floor(Math.random() * (totalDocs - count))
    
    return db[collection].find()
        .skip(randomSkip)
        .limit(count)
        .toArray()
}

print("\nRandom products using skip:")
getRandomDocuments("products", 2).forEach(printjson)

🔹 Cursor-based Pagination (More Efficient)

// More efficient pagination for large datasets
function getCursorPage(collection, lastId = null, pageSize = 5, sortField = "_id") {
    var query = {}
    
    // If we have a lastId, start from there
    if (lastId) {
        query[sortField] = { $gt: lastId }
    }
    
    var results = db[collection].find(query)
        .sort({ [sortField]: 1 })
        .limit(pageSize + 1)  // Get one extra to check if there's a next page
        .toArray()
    
    var hasNextPage = results.length > pageSize
    if (hasNextPage) {
        results.pop()  // Remove the extra document
    }
    
    var nextCursor = results.length > 0 ? results[results.length - 1][sortField] : null
    
    return {
        data: results,
        nextCursor: nextCursor,
        hasNextPage: hasNextPage
    }
}

// Usage
print("First page:")
var page1 = getCursorPage("products")
page1.data.forEach(printjson)

print("\nSecond page:")
var page2 = getCursorPage("products", page1.nextCursor)
page2.data.forEach(printjson)

print(`\nHas next page: ${page2.hasNextPage}`)

Performance Considerations

Best practices for efficient limit and skip operations

⚡ Performance Tips:

  • Index your sort fields: Always create indexes on fields used in sort()
  • Avoid large skip values: skip(10000) is slow - use cursor-based pagination
  • Combine with filters: Filter first, then limit for better performance
  • Use projection: Only return fields you need

🚫 Avoid These Patterns:

  • Large skip values without indexes
  • Sorting without indexes on sort fields
  • Using limit() without understanding your data size
// Good: Create index for sorted queries
db.products.createIndex({ price: -1 })
db.products.createIndex({ category: 1, price: -1 })

// Good: Efficient query with index
db.products.find({ category: "electronics" })
    .sort({ price: -1 })
    .limit(10)

// Bad: Large skip without index (slow for large collections)
// db.products.find().skip(10000).limit(10)  // Avoid this!

// Good: Use cursor-based pagination instead
function efficientPagination(minPrice = 0, limit = 10) {
    return db.products.find({ 
        category: "electronics",
        price: { $gt: minPrice }
    })
    .sort({ price: 1 })
    .limit(limit)
}

// Performance comparison function
function comparePerformance() {
    print("Testing performance...")
    
    // Method 1: Large skip (inefficient)
    var start = new Date()
    db.products.find().skip(1000).limit(10).toArray()
    var skipTime = new Date() - start
    
    // Method 2: Cursor-based (efficient)
    start = new Date()
    db.products.find({ _id: { $gt: ObjectId("507f1f77bcf86cd799439011") } })
        .limit(10).toArray()
    var cursorTime = new Date() - start
    
    print(`Skip method: ${skipTime}ms`)
    print(`Cursor method: ${cursorTime}ms`)
}

Practical Examples

Real-world applications of limit and skip

// Example 1: Blog post pagination
function getBlogPosts(page = 1, postsPerPage = 5) {
    var skip = (page - 1) * postsPerPage
    
    var posts = db.posts.find({ published: true })
        .sort({ publishDate: -1 })
        .skip(skip)
        .limit(postsPerPage)
        .toArray()
    
    var totalPosts = db.posts.countDocuments({ published: true })
    var totalPages = Math.ceil(totalPosts / postsPerPage)
    
    return {
        posts: posts,
        pagination: {
            currentPage: page,
            totalPages: totalPages,
            totalPosts: totalPosts,
            hasNext: page < totalPages,
            hasPrev: page > 1
        }
    }
}

// Example 2: Product search with pagination
function searchProducts(searchTerm, category = null, page = 1, limit = 10) {
    var query = {
        name: { $regex: searchTerm, $options: "i" }
    }
    
    if (category) {
        query.category = category
    }
    
    var skip = (page - 1) * limit
    
    var results = db.products.find(query)
        .sort({ price: 1 })
        .skip(skip)
        .limit(limit)
        .toArray()
    
    var totalResults = db.products.countDocuments(query)
    
    return {
        results: results,
        totalResults: totalResults,
        page: page,
        totalPages: Math.ceil(totalResults / limit)
    }
}

// Example 3: Leaderboard (top scores)
function getLeaderboard(gameId, topN = 10) {
    return db.scores.find({ gameId: gameId })
        .sort({ score: -1, timestamp: 1 })  // Highest score first, earliest time for ties
        .limit(topN)
        .toArray()
}

// Example 4: Recent activity feed
function getRecentActivity(userId, limit = 20) {
    return db.activities.find({
        $or: [
            { userId: userId },
            { followers: userId }
        ]
    })
    .sort({ timestamp: -1 })
    .limit(limit)
    .toArray()
}

// Usage examples
print("Blog posts page 1:")
var blogPage = getBlogPosts(1, 3)
blogPage.posts.forEach(post => print(`- ${post.title}`))

print("\nSearch results for 'phone':")
var searchResults = searchProducts("phone", null, 1, 5)
searchResults.results.forEach(product => print(`- ${product.name}: $${product.price}`))

print("\nTop 5 leaderboard:")
var leaderboard = getLeaderboard("game123", 5)
leaderboard.forEach((entry, index) => 
    print(`${index + 1}. ${entry.playerName}: ${entry.score}`)
)

🧠 Test Your Knowledge

What does db.users.find().skip(5).limit(3) return?

Which is more efficient for large datasets?

What should you do before using sort() with limit()?