SleekDB - A NoSQL Database made using PHP

SleekDB is a simple NoSQL database implementation using pure PHP that store data in plain JSON files.

It is not designed to handle heavy-load IO operations, it is designed to have a simple solution where all we need a database for managing few gigabytes of data. You can think of it as a database for static websites.

SleekDB works great as the database engine for low to medium traffic websites.

Features

  • Light-weight, faster

    Stores data in plain-text utilizing JSON format, no binary conversion needed to store or fetch the data.

  • Schema free data storage

    SleekDB does not require any schema meaning you can insert any types of data you want.

  • Query on nested properties

    Supports filter and conditions on nested properties of the JSON documents! If you write this where clause:

    where( 'post.author.role' '=', 'admin' )

    SleekDB will look for data at:

    {
    "post": {
      "author": {
        "role": "admin"
      }
    }
    }
  • Dependency free, only need PHP to run

    Supports PHP 5.5+, PHP 7+. Requires no third-party plugins or softwares.

  • Default caching layer

    SleekDB will serve data from cache by default and regenerate cache each time it creates, updates and deletes an object!

  • Filters: where, in, notIn, orWhere, sort, skip, limit and search

    Use multiple conditional comparisons, text search, sorting on multiple properties and nested properties.

  • Runs every where

    Runs perfectly on shared-servers or VPS too.

  • Easy to learn and implement

    SleekDB provides a very simple elegant API to handle all of your data.

  • Actively maintained

    SleekDB is actively maintained by @rakibtg. For support and other requirements contact.

  • Easily import/export or backup data.

Installation

To use SleekDB make sure that you have PHP up and running in your system, and SleekDB has write permission.

Using SleekDB in a PHP project

Composer Installation (recommended)

To install SleekDB using composer, open a terminal, cd into your project root directory where "composer.json" file lives and run this:

composer require rakibtg/sleekdb

SleekDB should be auto loaded into your app using the composer. Find SleekDB on packagist.

Install Manually (without composer)

  • Download the latest version and extract the ZIP file inside your project directory.
  • Import the SleekDB.php file where you want to use SleekDB.

    Example:

    require_once "../SleekDB/SleekDB.php";

To download older versions please check the releases.

Getting Started

Getting started with SleekDB is super easy. We keep data in a "store", which is similar to MySQL "table" or MongoDB "collection". To start working with data at first we create a new instance of SleekDB. Later, we create a "store" using the instantiated object to start working with data.

  1. To create the SleekDB instance we need a valid "path" where it can write data.
$dataDir = "/Users/username/documents/mydb";
  1. Once we have the data directory lets create the SleekDB store, which can be treated as the "table" in SQL databases. If the store doesn't exist then it will be created automatically.
$newsStore = \SleekDB\SleekDB::store('news', $dataDir);

Optionally you can pass a configuration array in the second parameter. Read more about configurations.

  1. Let's insert a new item like a news article.
// An array that we want to insert.
$newsInsertable = [
  "title" => "Google Pixel XL",
  "about" => "The unlocked biggest Pixel 2..."
];
$results = $newsStore->insert( $newsInsertable );

The results variable would contain all the inserted data and with the _id property.

Configurations

At this moment SleekDB only allows two configurations, which are "auto_cache" and "timeout". Configurations should be passed as an array in the second parameter while instantiating SleekDB, store's created from this object will follow the configurations we have provided.

Using Custom Configuration

You should pass the configurations array in the second parameter, example:

$newsStore = \SleekDB\SleekDB::store('news', $dataDir, [
  'auto_cache' => true,
  'timeout' => 120
]);

Let's talk about what this configurations do.

auto_cache

The auto_cache is set to true by default!

This tells SleekDB to cache the data of an unique database query and later re-use the cache for the same query. To keep the cached data synced with new data, SleekDB will delete all cache when we insert any new data to a store.

To disable it update the value of auto_cache to false in the config array.

Note that you can manually manage cache data with methods that SleekDB provides. Available caching method's are: makeCache(), useCache(), deleteCache() and deleteAllCache()

timeOut

Set timeout value, default value is 120 second.

Stores

Store is a simple directory where SleekDB will write all your data in JSON documents. "Store" is similar with the idea of "Table" in MySQL or "Collection" in MongoDB. You dont need to create a "store" manually, while you use the "store" method from the SleekDB object it will first check if the "store" directory exists or not, if not then it would be created instantly.

At this moment you can not rename a store, but you can do it manually using the File Browser of your OS or using the terminal.

Your first store

To start working with a store, at first we need to create an object using the "store" static method.

Later, we can use that object to work with data for that store.

  • Create an store

    $newsStore = \SleekDB\SleekDB::store('news', $dataDir);
  • Having multiple store; assuming we are working on a community site where need to have a users store.

    $userStore = \SleekDB\SleekDB::store('users', $dataDir);
  • Another store to keep all the posts shared by the user.

    $postStore = \SleekDB\SleekDB::store('posts', $dataDir);
  • Creating a new user

    $userStore->insert([
    'name' => 'Mike Doe',
    'email' => 'miked@example.com'
    ]);

In the above example we have created an user to understand the use case of a store in SleekDB. In this documentation later we will see more examples on this.

Deleting A Store

To delete a store use the deleteStore() method. It deletes a store and wipes all the data and cache it contains.

Example:

$userStore->deleteStore();

Keeping Store Conditions

When you run a query and use a action method like fetch, update or delete the conditions you have added for the active query will be reset to default.

But if you want to keep the condition parameters for query and perform additional operations then you may want to use the keepConditions() method.

Here is an example showing how you may fetch data and then update on the discovered documents without running an additional query:

// Find documents.
$result = $usersDB
  ->keepConditions() // Won't reset the active query state.
  ->where('products.totalBought', '>', 0)
  ->where('products.totalSaved', '>', 0);

// Fetch data.
$result->fetch();

// Update matched documents.
$result->update([
  'someRandomData' => '123',
]);

Insert Data

To insert data first you make a PHP array, and simply insert that array into a store.

Insert A Single Data Object

Using the insert() method we will insert a new data object. Example:

// Prepare a PHP array to insert.
$user = [
    'name' => 'Kazi Hasan',
    'products' => [
        'totalSaved' => 19,
        'totalBought' => 27
    ],
    'location' => [
        'town' => 'Nagar',
        'city' => 'Dhaka',
        'country' => 'Bangladesh'
    ]
];
// Insert the data.
$user = $usersDB->insert( $user );

Here, the insert() method will return the inserted object with the _id property which is generated by SleekDB.

Insert Multiple Data Object

Using the insertMany() method you can insert more than one data object at a time, example:

// Prepare users data.
$users = [
    [
        'name' => 'Russell Newman',
        'products' => [
        'totalSaved' => 5,
        'totalBought' => 3
        ],
        'location' => [
        'town' => 'Andreas Ave',
        'city' => 'Maasdriel',
        'country' => 'England'
        ]
    ],
    [
        'name' => 'Willard Bowman',
        'products' => [
        'totalSaved' => 0,
        'totalBought' => 0
        ],
    ],
    [
        'name' => 'Tommy Mendoza',
        'products' => [
        'totalSaved' => 172,
        'totalBought' => 54
        ],
    ],
    [
        'name' => 'Joshua Edwards',
        'phone' => '(382)-450-8197'
    ]
];
// Insert all data.
$usersDB->insertMany( $users );

The insertMany() method will return the inserted object with the _id property which is generated by SleekDB.

Fetch Data

To get data from the store we use the fetch() method. Example:

$usersDB->fetch();

The above command would query into the "users" store to fetch all the data.

Apply Filters and Conditions

where()

To filter data we use the where() method.

The where() method takes three arguments, those are:

where( $fieldName, $condition, $value );
  1. $fieldName

    The field name argument is the property that we want to check in our data object.

    As our data object is basically a JSON document so it could have nested properties.

    To target nested properties we use a single dot between the property/field name.

    Example: From our above users object if we want to target the "country" property of a user, then we would pass location.country in this argument, because "location" is the parent property of the "country" property in our data object.

  2. $condition

    To apply the comparison filters we use this argument.

    Allowed comparisonal conditions are:

    • = Match equal against data.
    • != Match not equal against data.
    • > Match greater than against data.
    • >= Match greater equal against data.
    • < Match less than against data.
    • <= Match less equal against data.
  3. $value

    Data to be used as against the property value of the JSON documents.

Example of using where() to filter data

To only get the user whose country is equal to "England" we would query like this:

$user = $usersDB->where( 'name', '=', 'Joshua Edwards' )->fetch();

You can use multiple where() conditions. Example:

$user = $usersDB
    ->where( 'products.totalSaved', '>', 10 )
    ->where( 'products.totalBought', '>', 20 )
    ->fetch();

orWhere()

orWhere(...) works as the OR condition of SQL. SleekDB supports multiple orWhere as object chain.

The orWhere() method takes three arguments same as where() condition, those are:

orWhere( $fieldName, $condition, $value );

Example:

$user = $usersDB
    ->where( 'products.totalSaved', '>', 10 )
    ->orWhere( 'products.totalBought', '>', 20 )
    ->fetch();

Multiple orWhere clause example:

$user = $usersDB->where( 'products.totalSaved', '>', 10 )
    ->orWhere( 'products.totalBought', '>', 20 )
    ->orWhere( 'products.shipped', '=', 1 )
    ->fetch();

in()

in(...) works as the IN clause of SQL. SleekDB supports multiple IN as object chain for different fields.

The in() method takes two arguments, those are:

in($fieldName = '', $values = []);
  1. $fieldName

    The field name argument is the property that we want to check in our data object.

    As our data object is basically a JSON document so it could have nested properties.

  2. $values

    This argument takes an array to match documents within its items.

Example:

$user = $usersDB->in('country', ['BD', 'CA', 'SE', 'NA'])->fetch();

notIn()

notIn(...) works as the opposite of in() method.

It will filter out all documents that has particular data items from the given array. SleekDB supports multiple notIn as object chain for different fields.

The notIn() method takes two arguments as in() method, those are:

notIn($fieldName = '', $values = []);

Example:

$user = $usersDB->notIn('country', ['IN', 'KE', 'OP'])->fetch();

Multiple notIn clause example with nested properties:

$user = $usersDB
    ->notIn('country', ['IN', 'KE', 'OP'])
    ->notIn('products.totalSaved', [100, 150, 200])
    ->fetch();

Edit Data

To edit a data object we would use the update() method.

The update method takes only one argument.

update($updateable);

Lets update the "totalBought" value of a user whose name is "Joshua Edwards"

$updateable = [
    'products' => [
        'totalBought' => 1
    ]
];
$usersDB->where( 'name', '=', 'Joshua Edwards' )->update( $updateable );

You can use more than one where condition if required.

Delete Data

To delete a data object we would use the delete() method. Example:

Lets delete the user whose name is "Joshua Edwards"

$usersDB->where( 'name', '=', 'Joshua Edwards' )->delete();

You can use more than one where condition if required.

Skip and Limit

To skip a set of record we will use the skip() method. Example:

// Skip the first 5 users.
$users = $usersDB->skip( 5 )->fetch();

To limit a set of record we will use the limit() method. Example:

// Fetch only 5 users.
$users = $usersDB->limit( 5 )->fetch();

Query Offset

To obtain the query offset feature we can chain skip() and limit() into one query. Example:

$users = $usersDB
    ->where( 'age', '>=', 18 )
    ->skip( 15 )
    ->limit( 5 )
    ->fetch();

The above query will skip first 15 records and will limit to next 5 records of data objects. This way we can also perform paginate.

Sort Data

To sort data objects we would use the orderBy() method.

The orderBy method takes two argument

orderBy($order, $orderBy);

Search Data

We can search data using the search() method. It utilizes the similar_text() function and works better on medium length string.

The search method takes two argument,

search($field, $keyword);
  1. $field argument receives the property name on which we want to perform the search.
  2. $keyword is the search keyword.

Lets search for users who lives in Canada.

$users = $usersDB
    ->search( 'location.country', 'Canada' )
    ->fetch();

To ensure proper search result we can search more than one property at a time. Example,

$users = $usersDB
    ->search( 'bio', 'Manufactured in Canada' )
    ->search( 'location.country', 'Canada' )
    ->where( 'active', '=', 1 )
    ->fetch();

Cache Management

The useCache() method would return the data from the cache storage, if cache dosent exists then it would fetch the result then creates the cache for later use and return the data. Example,

$user = $usersDB
    ->where( 'active', '=', 1 )
    ->where( 'location.country', '=', 'United States' )
    ->search( 'bio', 'PHP developer' )
    ->search( 'bio', 'SleekDB' )
    ->orderBy( 'desc', 'rank' )
    ->limit( 20 )
    ->useCache() // Use the cache data.
    ->fetch();

Re-generate Cache

To re-generate the cache for a query we would use the makeCache() method.

Its more like the useCache() method but the only difference is that instead of looking for existing cache data it would replace the old cache by generating a new cache from fresh data fetched. Example,

$user = $usersDB
    ->search( 'bio', 'SleekDB' )
    ->orderBy( 'desc', 'rank' )
    ->skip( 80 )
    ->limit( 20 )
    ->makeCache() // Re-generate the cache data.
    ->fetch();

Delete Cache

To delete the cache of a query we would use the deleteCache() method. Example,

$user = $usersDB
    ->search( 'bio', 'SleekDB' )
    ->orderBy( 'desc', 'rank' )
    ->skip( 80 )
    ->limit( 20 )
    ->deleteCache();

Note that if you need to get the data please add the fetch() method.

Delete All Cache

To delete all cache use the deleteAllCache() method. Example,

$usersDB->deleteAllCache();

Contributing

  • Fork SleekDB
  • Create your feature branch git checkout -b feature/my-new-feature
  • Commit your changes git commit -am 'Added some feature'
  • Push to the branch git push origin feature/my-new-feature
  • Create new Pull Request

🎉 Release Notes

📢 Optimizations, new clause methods and more control

SleekDB 1.5.0 comes with few important optimizations and with other features that will make it more easier to manage data. This is a recommended update if you are using an older version of SleekDB.

No breaking changes from 1.0.3 to 1.5.0

  • 💪 Improving document discovery process

    Starting from version 1.5.0 SleekDB will discover new documents without affecting the _id serializer, that means it will need to do a lot less work than before. That makes it more faster less memory hungry than ever before.

  • 🐍 orWhere() clause method

    It will work as the OR condition of SQL. SleekDB supports multiple orWhere as object chain.

    $user = $usersDB->where( 'products.totalSaved', '>', 10 )
      ->orWhere( 'products.totalBought', '>', 20 )
      ->orWhere( 'products.shipped', '=', 1 )
      ->fetch();
  • 😍 in() clause method

    It work like the IN clause of SQL. SleekDB supports multiple in() as object chain for different fields.

    $user = $usersDB
      ->in('country', ['BD', 'CA', 'SE', 'NA'])
      ->in('products.totalSaved', [100, 150, 200])
      ->fetch();
  • 😎 notIn() clause method

    It works as the opposite of in() method.

    It will filter out all documents that has particular data items from the given array. SleekDB supports multiple notIn as object chain for different fields.

    $user = $usersDB
      ->notIn('country', ['IN', 'KE', 'OP'])
      ->notIn('products.totalSaved', [100, 150, 200])
      ->fetch();
  • 🤗 Keeping Query State

    If you want to keep the condition parameters for query and perform additional operations then you may want to use the keepConditions() method.

    Here is an example showing how you may fetch data and then update on the discovered documents without running an additional query:

    // Find documents.
    $result = $usersDB
      ->keepConditions() // Won't reset the active query state.
      ->where('products.totalBought', '>', 0)
      ->where('products.totalSaved', '>', 0);
    
    // Fetch data.
    $result->fetch();
    
    // Update matched documents.
    $result->update([
      'someRandomData' => '123',
    ]);

Github release note: https://github.com/rakibtg/SleekDB/releases/tag/1.5.0

About & Contact

We would love to see how you are using the database, if you have implemented something or how it is working for you.

What changes will make you more interested.

If you want to submit a bug feel free to create a new issue or email me @ rakibtg [-at-] gmail [-dot-] com

About

SleekDB is actively maintained by @rakibtg(Twitter). Let me know with a tweet if you love or hate SleekDB 😄, or if you have any question mail me or tweet to my twitter handle.

Versions