herdianrony/mongolite

MongoDB-like interface with SQLite backend

Installs: 3

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/herdianrony/mongolite

v1.0.0 2025-09-28 05:21 UTC

This package is auto-updated.

Last update: 2025-12-28 08:48:27 UTC


README

PHP Version License

High-performance MongoDB-compatible query engine with SQLite backend

MongoLite is a lightweight, production-ready library that provides MongoDB-style queries and aggregations using SQLite as the storage engine. Originally developed as part of Cockpit CMS, it has been extracted and enhanced as a standalone library.

๐Ÿ” About

This library was originally part of the Cockpit CMS project. It has been extracted, improved, and is now maintained as a separate package for broader use in PHP applications that need a lightweight, file-based NoSQL solution.

โœจ Features

๐Ÿ” Query Engine

  • 25+ Query Operators: Complete support for MongoDB query syntax
  • Advanced Filtering: $and, $or, $not, $nor, $where, $expr
  • Comparison Operators: $eq, $ne, $gt, $gte, $lt, $lte
  • Array Operators: $in, $nin, $all, $size, $elemMatch
  • Pattern Matching: $regex, $text with fuzzy search
  • Field Validation: $exists, $type, $mod

๐Ÿ“Š Aggregation Framework

  • 18+ Pipeline Stages: Complete aggregation pipeline support
  • 10 Accumulator Operators: $sum, $avg, $min, $max, $first, $last, $push, $addToSet, $stdDevPop, $stdDevSamp
  • Data Transformation: $project, $addFields, $unset, $unwind
  • Grouping & Sorting: $group, $sort, $sortByCount, $bucket
  • Sampling & Analysis: $sample, $facet, $count
  • Joins: $lookup for data relationships

๐ŸŒ Geospatial Support

  • Location Queries: $near, $geoWithin, $geoIntersects
  • Geometric Shapes: Point, Polygon, Circle, Box support
  • Distance Calculations: Haversine formula for accurate distances
  • Aggregation Integration: $geoNear pipeline stage

๐Ÿ“ค Output Stages

  • Data Export: $out stage for collection replacement
  • Data Merging: $merge stage with conflict resolution
  • Flexible Options: whenMatched, whenNotMatched behaviors

๐Ÿ”’ Security & Performance

  • SQL Injection Protection: Comprehensive input sanitization
  • Memory Efficient: Optimized for large dataset processing
  • Production Ready: Tested with 1000+ record datasets
  • Error Resilient: Graceful handling of edge cases

๐Ÿš€ Quick Start

Basic Usage

<?php
require_once 'MongoLite/Database.php';

use MongoLite\Database;

// Create database
$db = new Database('/path/to/database.db');
$collection = $db->selectCollection('users');

// Insert documents
$collection->insert([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'age' => 30,
    'location' => ['coordinates' => [-74.0059, 40.7128]]
]);

// Query documents
$users = $collection->find(['age' => ['$gte' => 25]])->toArray();

// Update documents
$collection->update(['name' => 'John Doe'], ['$set' => ['age' => 31]]);

// Delete documents
$collection->remove(['age' => ['$lt' => 18]]);

Advanced Queries

// Complex filtering
$results = $collection->find([
    '$and' => [
        ['age' => ['$gte' => 18]],
        ['$or' => [
            ['status' => 'active'],
            ['premium' => true]
        ]]
    ]
])->toArray();

// Text search with fuzzy matching
$searchResults = $collection->find([
    'description' => [
        '$text' => [
            '$search' => 'mongodb query',
            '$minScore' => 0.8
        ]
    ]
])->toArray();

// Geospatial queries
$nearbyUsers = $collection->find([
    'location' => [
        '$geoWithin' => [
            '$center' => [[-74.0059, 40.7128], 1000] // 1km radius
        ]
    ]
])->toArray();

Aggregation Pipeline

// Business intelligence aggregation
$analytics = $collection->aggregate([
    // Filter active users
    ['$match' => ['status' => 'active']],
    
    // Group by department
    ['$group' => [
        '_id' => '$department',
        'employee_count' => ['$sum' => 1],
        'avg_salary' => ['$avg' => '$salary'],
        'salary_std_dev' => ['$stdDevPop' => '$salary'],
        'top_performer' => ['$first' => '$name'],
        'all_employees' => ['$push' => '$name']
    ]],
    
    // Sort by average salary
    ['$sort' => ['avg_salary' => -1]],
    
    // Add calculated fields
    ['$addFields' => [
        'salary_category' => [
            '$cond' => [
                'if' => ['$gte' => ['$avg_salary', 75000]],
                'then' => 'High',
                'else' => 'Standard'
            ]
        ]
    ]],
    
    // Export results
    ['$out' => 'department_analytics']
])->toArray();

Geospatial Operations

// Find stores near a location
$nearbyStores = $collection->aggregate([
    ['$geoNear' => [
        'near' => ['coordinates' => [-73.9857, 40.7484]], // Times Square
        'distanceField' => 'distance_meters',
        'maxDistance' => 5000, // 5km radius
        'query' => ['type' => 'retail']
    ]],
    ['$project' => [
        'name' => 1,
        'address' => 1,
        'distance_km' => ['$divide' => ['$distance_meters', 1000]]
    ]],
    ['$sort' => ['distance_meters' => 1]],
    ['$limit' => 10]
])->toArray();

// Point in polygon check
$inBoundary = $collection->find([
    'delivery_zone' => [
        '$geoIntersects' => [
            '$geometry' => [
                'type' => 'Polygon',
                'coordinates' => [[[0,0], [10,0], [10,10], [0,10], [0,0]]]
            ]
        ]
    ]
])->toArray();

๐Ÿ“‹ API Reference

Database Class

$db = new Database($path, $options = []);

// Collection management
$collection = $db->selectCollection($name);
$db->createCollection($name);
$db->dropCollection($name);
$names = $db->getCollectionNames();

// Security
$safeName = $db->sanitizeCollectionName($name);

// Utility
$db->vacuum(); // Optimize database
$db->drop();   // Delete database

Collection Class

// CRUD Operations
$result = $collection->insert($document);
$count = $collection->insertMany($documents);

$cursor = $collection->find($criteria, $projection);
$document = $collection->findOne($criteria, $projection);

$collection->update($criteria, $data, $options);
$collection->remove($criteria, $options);

// Aggregation
$cursor = $collection->aggregate($pipeline);

// Utility
$count = $collection->count($criteria);
$collection->drop();

Cursor Class

// Iteration
foreach ($cursor as $document) {
    // Process document
}

// Conversion
$array = $cursor->toArray();

// Pagination
$cursor->skip($offset)->limit($count);
$cursor->sort(['field' => 1]); // 1 = ASC, -1 = DESC

๐Ÿ—๏ธ Architecture

Core Components

MongoLite/
โ”œโ”€โ”€ Database.php          # Database connection and management
โ”œโ”€โ”€ Collection.php        # Collection operations and CRUD
โ”œโ”€โ”€ Cursor.php           # Query result iteration
โ”œโ”€โ”€ UtilArrayQuery.php   # Query engine and operators
โ”œโ”€โ”€ Projection.php       # Field projection logic
โ””โ”€โ”€ Aggregation/
    โ”œโ”€โ”€ Cursor.php       # Aggregation pipeline processor
    โ””โ”€โ”€ ValueAccessor.php # Nested field manipulation

Storage Layer

  • Backend: SQLite with JSON document storage
  • Schema: Dynamic document structure in BLOB fields
  • Indexing: Automatic SQLite indexing for performance
  • ACID: Full transaction support via SQLite

Query Processing

  1. Parse: MongoDB query โ†’ Internal AST
  2. Validate: Security checks and sanitization
  3. Transform: AST โ†’ SQLite query + Filters
  4. Execute: SQLite query with post-processing
  5. Return: MongoDB-compatible results

๐Ÿ”ง Advanced Configuration

Database Options

$options = [
    PDO::ATTR_TIMEOUT => 30,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];

$db = new Database('/path/to/db.sqlite', $options);

Memory Database

// In-memory database for testing
$db = new Database(':memory:');

Custom Functions

// Register custom SQLite functions
$db->connection->sqliteCreateFunction('custom_func', function($value) {
    return strtoupper($value);
});

๐Ÿ“Š Performance Guidelines

Optimization Tips

  1. Use Projections: Limit returned fields

    $collection->find($criteria, ['name' => 1, 'email' => 1]);
  2. Efficient Filtering: Place most selective criteria first

    ['status' => 'active', 'age' => ['$gte' => 18]] // status first if more selective
  3. Limit Results: Use pagination for large datasets

    $collection->find($criteria)->skip(0)->limit(50);
  4. Aggregation Optimization: Filter early in pipeline

    [
        ['$match' => $criteria],      // Filter first
        ['$group' => $grouping],      // Then group
        ['$sort' => $sorting]         // Finally sort
    ]

Memory Management

// Process large datasets in chunks
$offset = 0;
$limit = 1000;

while (true) {
    $batch = $collection->find($criteria)
        ->skip($offset)
        ->limit($limit)
        ->toArray();
    
    if (empty($batch)) break;
    
    // Process batch
    foreach ($batch as $document) {
        // Handle document
    }
    
    $offset += $limit;
}

๐Ÿ”’ Security Best Practices

Input Validation

// โœ… Good: Use sanitization
$safeName = $db->sanitizeCollectionName($userInput);
if ($safeName === null) {
    throw new InvalidArgumentException('Invalid collection name');
}

// โœ… Good: Validate field names
$allowedFields = ['name', 'email', 'age'];
$projection = array_intersect_key($userProjection, array_flip($allowedFields));

Query Safety

// โœ… Good: Use MongoDB operators
$criteria = [
    'email' => ['$regex' => preg_quote($searchTerm)]
];

// โŒ Avoid: String interpolation in queries
// $criteria = ['email' => '/' . $searchTerm . '/i']; // Potentially unsafe

๐Ÿงช Testing

Unit Tests

<?php
use MongoLite\Database;

// Test setup
$db = new Database(':memory:');
$collection = $db->selectCollection('test');

// Test insert
$doc = ['name' => 'Test', 'value' => 123];
$collection->insert($doc);

// Test query
$result = $collection->findOne(['name' => 'Test']);
assert($result['value'] === 123);

// Test aggregation
$stats = $collection->aggregate([
    ['$group' => [
        '_id' => null,
        'total' => ['$sum' => '$value']
    ]]
])->toArray();

assert($stats[0]['total'] === 123);

Performance Testing

// Benchmark aggregation performance
$start = microtime(true);

$results = $collection->aggregate([
    ['$match' => ['status' => 'active']],
    ['$group' => ['_id' => '$category', 'count' => ['$sum' => 1]]],
    ['$sort' => ['count' => -1]]
])->toArray();

$elapsed = microtime(true) - $start;
echo "Aggregation took: " . round($elapsed, 3) . "s\n";

๐Ÿค MongoDB Compatibility

Supported Operations

Feature MongoDB MongoLite Notes
Query Operators โœ… โœ… 25+ operators
Aggregation Pipeline โœ… โœ… 18+ stages
Geospatial Queries โœ… โœ… Point, Polygon support
Text Search โœ… โœ… Fuzzy matching
Transactions โœ… โœ… Via SQLite ACID
Sharding โœ… โŒ Single database file
Replica Sets โœ… โŒ SQLite limitation

Migration from MongoDB

// MongoDB syntax works directly
$results = $collection->find([
    'age' => ['$gte' => 21],
    'status' => ['$in' => ['active', 'pending']]
])->toArray();

// Aggregation pipelines are identical
$analytics = $collection->aggregate([
    ['$match' => ['type' => 'user']],
    ['$group' => [
        '_id' => '$department',
        'count' => ['$sum' => 1],
        'avgAge' => ['$avg' => '$age']
    ]]
])->toArray();

๐Ÿ”ง Troubleshooting

Common Issues

Q: "Call to undefined function"

// Ensure all required files are included
require_once 'MongoLite/Database.php';
require_once 'MongoLite/Collection.php';
require_once 'MongoLite/UtilArrayQuery.php';

Q: "Permission denied" on database file

# Fix file permissions
chmod 644 /path/to/database.db
chmod 755 /path/to/database/directory

Q: "Invalid collection name" error

// Use sanitization for user input
$safeName = $db->sanitizeCollectionName($userInput);
if ($safeName) {
    $collection = $db->selectCollection($safeName);
}

Q: Poor aggregation performance

// Optimize pipeline order
$pipeline = [
    ['$match' => $criteria],     // Filter first
    ['$group' => $grouping],     // Then group  
    ['$sort' => $sorting],       // Sort last
    ['$limit' => 100]            // Limit results
];

Debug Mode

// Enable SQLite logging for debugging
$db->connection->sqliteCreateFunction('debug_log', function($message) {
    error_log("MongoLite Debug: $message");
    return $message;
});

๐Ÿ“„ License

MIT License - see LICENSE file for details.

๐Ÿ™ Credits

  • Original development team at Cockpit CMS
  • Current maintainers: [Your Name/Organization]
  • Contributors: [List of contributors if any]

Ready to get started? Check out the Quick Start guide above!

๐Ÿ”— Related Projects

  • Cockpit CMS - The original project where MongoLite was developed
  • MongoLite - This standalone version