Beginner C++ Database Tutorial: How to use ObjectBox

Beginner C++ Database Tutorial: How to use ObjectBox

Introduction

As a direct follow up from the ObjectBox database installation tutorial, today we’ll code a simple C++ example app to show how the database can be used. Before starting to program, let’s briefly overview what we want to achieve with this tutorial and what is the best way to work through it.

Overview of the app we want to build

In short, we will make a console calculator app with an option to save results into memory. These will be stored as objects of the Number class. Every Number will also have an ID for easy reference in future calculations. Apart from the function to make calculations, we will create a function to enter memory. It will list all the database entries and have an option to clear memory. By coding all of this, we will make use of such standard ObjectBox operations as put, get, getAll and removeAll.

Our program will consist of seven files: 

  • the FlatBuffers schema file, that defines the model of a class we want to store in the database
  • the header file, for class function definitions
  • the source file, for function implementation
  • the four files with objectbox binding code that will be created by objectbox-generator

How to use this tutorial

While looking at coding examples is useful in many cases, the best way to learn such a practical skill like programming is to solve problems independently. This is why we included an exercise for each step. You are encouraged to make the effort and do each of them, even if you don’t know the answer straight away. Only move to the next step after you test each part of your program and make sure that everything works as intended. Ideally, you should only use the code snippets presented here to check yourself or look for hints when you feel stuck. Bear in mind that sometimes there might be several different ways to achieve the same results. So if something that we ask you to do in this tutorial doesn’t work for you, try to come up with your own solution.

How to create the FlatBuffers file?

First, we’ll create the FlatBuffers schema (.fbs) for our app. This is required for the objectbox-generator to generate binding code that will allow us to use the ObjectBox library in our project. 

The FlatBuffers schema consists of a table, which defines the object we want to store in the database, and the properties of this object. Each property consists of a name and a type. We want to keep our example very simple, so just two properties is enough.

  1. To replicate a calculator’s memory, we want ObjectBox to store some numbers. We can define the Number object by giving the table a corresponding name.
  2. Inside the table, we want to have two properties: id and contents. The contents of each Number object is the number itself (double), while id is an ulong that our program will assign to each of them for easy identification.

Exercise: create a file called numbers.fbs and define the table in the format

Reveal code

Generating binding code

Now that the FlatBuffers file is ready, we can generate the binding code. To do this, run the objectbox-generator for our FlatBuffers file:

The following files will be generated:

  • objectbox-model.h
  • objectbox-model.json
  • numbers.obx.hpp
  • numbers.obx.cpp

The header file

This is where the main chunk of our code will be. It will contain the Calculator class and all the function definitions.

  1. Start by including the three ObjectBox header files: objectbox.hpp, objectbox-model.h and numbers.obx.hpp. Our whole program will be based on one class, called Calculator. It should only have two private members: Store and Box. Store is a reference to the database and will manage Boxes. Each Box stores objects of a particular class. In this example, we only need one Box. Let’s call it numberBox, as it will store Numbers that we want to save in the memory of our calculator.

Exercise: create a file called calculator.hpp and define the Calculator class with two private members: reference to the obx library member Store and a Box of Numbers.

Reveal code

2. After the constructor, we define the run function. It will be responsible for the menu of our program. There should be two main options: to perform calculations and enter memory. As discussed above, we want this app to do two things: perform calculations and show memory. We’ll define these as separate functions, called Calculate and Memory. The first one is quite standard, so we won’t go into a detailed explanation here. The only thing you should keep in mind is that we need to account for the case when the user wants to  operate on a memory item. To deal with this, we’ll process input in a function called processInput.

Exercise: define the parametrised constructor which takes a reference to Store as a parameter. Then define the run and Calculate functions.

Reveal code

3. The final part of this function is for saving results into memory. We start by asking the user if they want to do that. If the answer is positive, we create a new instance of Number and set the most recent result as a value of its contents. To save our object in the database, we can operate with put(object) on our Box. put is one of the standard ObjectBox operations, which is used for creating new objects and overwriting existing ones. 

Exercise: create an option to store the result in memory, making use of the ObjectBox put operation.

Reveal code

4. Next, we should define processInput, which will read input as a string and check whether it has the right format. Now, to make it recognise the memory items, we have to come up with a standard format for these. Remember, we defined an ID property for our Numbers. Every number in our database has an ID, so we can refer to them as, e.g. m1, m2, m3 etc. To read the numbers from memory, we can make use of the get(obx_id) operation. It returns a unique pointer to the corresponding Number, whose contents we need to access and use as our operand.

Exercise: define the processInput function, which detects when something like m1 was used as an operand and updates x, y, and op according to the input.

Reveal code

5. The last function in our header file will be Memory. It should list all the numbers contained in the database and have an option to clear data. We can read all the database entries by calling the getAll ObjectBox operator. It returns a vector of unique pointers. To clear memory, you can simply operate with removeAll on our Box.

Exercise: define the Memory function, which lists all the memory items, and can delete all of them by request.

Reveal code

The source file

To tie everything together, we create a source (.cpp) file. It should contain only the main function that initialises the objectbox model, creates an instance of the Calculator app, and runs it. To create the ObjectBox model, use

then passing options as a parameter when you initialise the Store.

Exercise: create the source file

Reveal code

Final notes

Now you can finally compile and run your application. At this point, a good exercise would be to try and add some more functionality to this project. Check out the ObjectBox C++ documentation to learn more about the available operations.

After you’ve mastered ObjectBox DB, why not try ObjectBox Sync? Here is another tutorial from us, showing how easily you can sync between different instances of your cross platform app.

Other than that, if you spot any errors in this tutorial or if anything is unclear, please come back to us. We are happy to hear your thoughts.

Beginner C++ tutorial: ObjectBox installation

Beginner C++ tutorial: ObjectBox installation

This ObjectBox beginner tutorial is for people who have limited knowledge of C++ development (no prior experience with external libraries is required). It will walk you through the installation process of all the development tools needed to get started with ObjectBox on Windows. By the way, ObjectBox is a database with intuitive native APIs, so it won’t take you long to start using it.

Firstly, we will need to set up a Linux subsystem (WSL2) and install such tools as:

  • CMake, which will generate build files from the ObjectBox source code to work on Linux;
  • Git, which will download the source code from the ObjectBox repository.

Then, we will install ObjectBox and run a simple example in Visual Studio Code.

Windows Subsystem for Linux (WSL2)

In this section, you will set up a simple Linux subsystem that you can use to build Objectbox in C++.

  1. Install WSL (Note: this requires a reboot; it also configures a limited HyperV that may cause issues with e.g. VirtualBox).
    Warning: to paste e.g. a password to the Ubuntu setup console window, right-click the title bar and select Edit → Paste. CTRL + V may not work.
  2. (optional, but recommended) install Windows Terminal from Microsoft Store and use Ubuntu from there (does not have the copy/paste issue, also supports terminal apps better).
Windows Terminal in the Microsoft Store

3. Within Windows Terminal, open Ubuntu by choosing it from the dropdown menu.

Drop-down menu in Windows Terminal, through which a new tab for Ubuntu can be opened

4. Get the latest packages and upgrade:

5. Install build tools

Install ObjectBox using CMake

Now that you have WSL2 and all the packages, we can switch to VS Code and install ObjectBox with the help of CMake.

  1. In Ubuntu, create a new directory and then open it in Visual Studio Code:

2. Install the following extensions:

Extensions tab in Visual Studio Code, showing what needs to be installed in this tutorial: C/C++, CMake Tools and Remote - WSL

3. Create a text file called CMakeLists.txt with the following code. It will tell CMake to get the ObjectBox source code from its Git repository and link the library to your project.

4. Create a simple main.cpp file that will help us verify the setup:

5. Follow this official guide for VS code and CMake to select Clang as the compiler, configure and build ObjectBox. As a result, .vscode and build folders will be generated. So your directory should now look like this:

Explorer tab in Visual Studio Code, showing the two new folders that were generated after a successful build

Running the tasks-list app example

Finally, we can check that everything works and run a simple example.

1. Click the “Select target to launch” button on the status bar and select “myapp” from the dropdown menu. Then launch it. You should see it output the correct version as in the screenshot.

"Select launch target" menu in Visual Studio Code
Output of main.cpp, verifying the version of ObjectBox used and demonstrating that the C++ build files were generated correctly.

2. Before proceeding with the example, you need to download the most recent ObjectBox generator for Linux from releases. Then come back to the Windows Terminal and type

to open the current directory in Windows Explorer. Copy the objectbox-generator file in there.

3. Back in VS Code, you should now run the generator for the example code:

If you get a “permission denied” error, try this to make the generator file executable for your user:

4. Now choose objectbox-c-examples-tasks-cpp-gen as the target and run it. You should see the menu of a simple to-do list app as shown on the screenshot. It stores your tasks, together with their creation time and status. Try playing around with it and exploring the code of this example app to get a feel of how ObjectBox can be used.

Output of the Objectbox C++ tasks-list app example showing its menu with available commands

Note: if you see a sync error (e.g. Can not modify object of sync-enabled type “Task” because sync has not been activated for this store), please delete the first line from the tasklist.fbs file and run the objectbox generator once again. Or, if you want to try sync, apply for our Early Access Data Sync. There is a separate example (called objectbox-c-examples-tasks-cpp-gen-sync) that you can run after installing the Sync Server.

SQLite and SQLite alternatives – a comprehensive overview

SQLite and SQLite alternatives – a comprehensive overview

SQLite and SQLite alternatives - databases for the Mobile and IoT edge

Updated in March 2022: comparison of mobile databases / edge databases

Digitalization is still on the rise, and so is the number of digital devices (from 15 billion mobile devices operating + 13 billion connected IoT devices in 2021 already). Due to this, data volumes grow accordingly (estimated 79 zettabytes of data created in 2021), and centralised computing can no longer support the current needs. This has led to new challenges in computing and subsequently is leading to a shift from the cloud to the edge.

Consequently, the Edge Computing market is expected to grow by 14.8% in 2022 and the years to come (IDC 2022). Hence, there is an increased need for data persistence on the edge. Data flows to / from and between edge devices can be done with Edge Databases and Data Sync. For this reason, we have a look at the edge database market in the following review.

Databases

While being quite established and somewhat saturated, the database market is still growing consistently and significantly. The reason is that databases are at the core of almost any digital solution, and therefore never out of fashion. With the rapid evolvements in the tech industry, however, databases need to evolve too. This, in turn, yields new database types and categories. We have seen the rise of NoSQL databases in the last 20 years, and more recently some novel database technologies, like graph databases and time-series databases. Both the shift from a centralised towards a decentralised paradigm and the growing number of restricted devices call for a new type of database. Thus, we expect Edge databases to become more prominent in the coming years.

What is an Edge Database?

Edge databases are a type of databases that are optimised for local data storage on restricted devices, like embedded devices, Mobile, and IoT. Because they run on-device, they need to be especially resource-efficient (e.g. with regards to battery use, CPU consumption, memory, and footprint). The term “edge database” is becoming more widely-used every year, especially in the IoT industry. In IoT, the difference between cloud-based databases and ones that run locally (and therefore support Edge Computing) is crucial.

What is a Mobile Database?

We look at mobile databases as a subset of edge databases that run on mobile devices. The difference between the two terms lies mainly in the supported operating systems / types of devices. Unless Android and iOS are supported, an edge database is not really suited for the mobile device / smartphone market. In this article, we will use the term “mobile database” only as “database that runs locally on a mobile (edge) device and stores data on the device”. Therefore, we also refer to it as an “on-device” database.

What are the advantages and disadvantages of working with SQLite?

SQLite is a relational database that is clearly the most established database suitable to run on edge devices. Moreover, it is probably the only “established” mobile database. It was designed in 2000 by Richard Hipp and has been embedded with iOS and Android since the beginning. Now let’s have a quick look at its main advantages and disadvantages:

Advantages  Disadvantages
  • 20+ years old (should be stable ;))
  • Toolchain, e.g. DB browser
  • No dependencies, is included with Android and iOS
  • Developers can define exactly the data schema they want
  • Full control, e.g. handwritten SQL queries
  • SQL is a powerful and established query language, and SQLite supports most of it
  • Debuggable data: developers can grab the database file and analyse it
  • 20+ years old ( less state-of-the-art tech)
  • Using SQLite means a lot of boilerplate code and thus inefficiencies ( maintaining long running apps can be quite painful)
  • No compile time checks (e.g. SQL queries)
  • SQL is another language to master, and can impact your app’s efficiency / performance significantly…
  • The performance of SQLite is unreliable
  • SQL queries can get long and complicated
  • Testability (how to mock a database?)
  • Especially when database views are involved, maintainability may suffer with SQLite

 

What are the SQLite alternatives?

There are a bunch of options for making your life easier, if you want to use SQLite. You can use an object abstraction on top of it (ORM), for instance greenDAO, to avoid writing lots of SQL. However, you will typically still need to learn SQL and SQLite at some point. So what you really want is a full blown database alternative, like any of these: Couchbase Lite, Interbase, LevelDB, ObjectBox, Oracle Berkeley DB, Mongo Realm, SnappyDB, SQL Anywhere, or UnQLite.

While SQLite really is designed for small devices, people do run it on the server / cloud too. However, for server / cloud databases, there are a lot of alternatives you can use as a replacement like e.g. MySQL, MongoDB, or Cloud Firestore.

Bear in mind that, if you are looking to host your database centrally with apps running on small distributed devices (e.g. mobile apps, IoT apps, any apps on embedded devices etc.), there are some difficulties. Firstly, this will result in higher latency, i.e. slow response-rates. Secondly, the offline capabilities will be highly limited or absent. As a result, you might have to deal with increased networking costs, which is not only reflected in dollars, but also CO2 emissions. On top, it means all the data from all the different app users is stored in one central place. This means that any kind of data breach will affect all your and your users’ data. Most importantly, you will likely be giving your cloud / database provider rights to that data. (Consider reading the general terms diligently). If you care about privacy and data ownership, you might therefore want to consider an Edge Database. This way you can limit what data you sync to a central instance (like the cloud). 

SQLite alternatives Comparison Matrix

To give you an overview, we have compiled a comparison table including SQLite and SQLite alternatives. In this matrix we look at databases that we believe are apt to run on edge devices. Our rule of thumb is the databases’ ability to run on Raspberry Pi type size of devices.

Edge Database Android / iOS Type of data stored Sync Central Sync P2P Offline Sync Data level encryption License / business model Flutter support Short description Minimum Footprint size Company
Azure SQL Edge No Relational DB for IoT No No No will provide encryption Proprietary No Designed as a SQL database for the IoT edge; however, due to the footprint it is no edge database 500 MB+ Microsoft
Couchbase Lite Android / iOS JSON Documents / NoSQL db Yes Yes No Database encryption with SQLCipher (256-bit AES) Apache 2.0 Unofficial Flutter plugin for Couchbase Lite Community Editionavialable Embedded / portable database with P2P and central synchronization (sync) support. Secure SSL. < 3,5 MB Couchbase
extremeDB iOS In-memory relational DB, hybrid persistence No No No AES encryption Proprietary No Embedded relational database < 1 MB McObject LLC
InterBase ToGo / IBLite Android / iOS Relational No No No 256 bit AES strength encryption Proprietary No Embeddable SQL database. < 1 MB Embarcadero
LevelDB Android / iOS Key-value pairs / NoSQL db No No No No New BSD Unofficial client that is very badly rated Portable lightweight key-value store, NoSQL, no index support; benchmarks from 2011 have been removed unfortunately < 1 MB LevelDB
Team
LiteDB Android / iOS (with Xamarin only) NoSQL document store, fully wirtten in .Net No No No Salted AES MIT license No A .Net embedded NoSQL database < 1 MB LiteDB team
Mongo Realm (acquired by Mongo in 2019) Android / iOS Object Database Yes, tied to using MongoDB servers No No Yes Proprietary with Apache 2.0 License APIs Unofficial Flutter plugin, in Alpha according to their website [11.03.2022] Embedded object database 5 MB+ MongoDB Inc.
ObjectBox Android / iOS / Linux / Windows / any POSIX Object-oriented NoSQL edge database for high-performance on edge devices in Mobile and IoT Yes WIP Yes transport encryption; additional encryption upon request Apache 2.0 and Proprietary Yes High-performance NoSQL Edge Database with out-of-the-box Data Sync for Mobile and IoT; fully ACID compliant; benchmarks available. < 1 MB ObjectBox
Oracle Database Lite Android / iOS Relational Yes Yes No 128-bit AES Standard encrytion Proprietary No Portable with P2P and central sync support as well as support for sync with SQLite < 1 MB Oracle Corporation
redis DB No K/V in-memory store, typically used as cache No No No TLS/SSL-based encryption can be enabled for data in motion. Three clause BSD license, RSAL and Proprietary Unofficial redis Dart client available High-performance in-memory Key Value store with optional durability An empty instance uses ~ 3MB of memory redislabs (the original author of redis left in 2020)
SQL Anywhere Android / iOS Relational Dependent No No AES-FIPS cipher encryption for full database or selected tables Proprietary No Embedded / portable database with central snyc support with a stationary database   Sybase iAnywhere
SQLite embedded on iOS and Android Relational No No No No, Use SQLCipher to encrypt SQLite Public domain Flutter plugins (ORMs) for SQLite, but nothing from Hwaci C programming library; probably 90% market share (very personal assumption, 2016) < 1 MB Hwaci
SQL Server Compact Android / iOS Relational No No No Yes Proprietary No Small-footprint embedded / portable database for Microsoft Windows mobile devices and desktops, supports synchronization with Microsoft SQL Server 2 MB Microsoft
UnQLite Android / iOS Key-value pairs / JSON store / NoSQL db No No No 128-bit or 256-bit AES standard encryption 2-Clause BSD not yet; might be coming though; there was a 0.0.1 released some time ago Portable lightweight embedded db; self-contained C library without dependency. ~ 1.5 MB Symisc systems

Star this matrix on GitHub. If you are interested in an indication of the diffusion rate of databases and mobile databases, check out the following database popularity ranking: http://db-engines.com/en/ran.

Is there anything we’ve missed? What do you agree and disagree with? Please share your thoughts with us via Twitter or email us on contact[at]objectbox.io. 

Make sure to check out the ObjectBox Database & try out ObjectBox Sync. You can get started in minutes. More than 1,000,000 developers already use this Edge Database designed specifically for high performance on embedded devices.