Data Viewer for Objects – announcing ObjectBox Admin

Data Viewer for Objects – announcing ObjectBox Admin

ObjectBox Admin (Docker container) allows you to analyze ObjectBox databases that run on desktop and server machines. Releasing ObjectBox Admin as a standalone Docker image makes it possible to run Admin on a larger number of platforms.

ObjectBox Admin is available as a Linux x86_64 Docker image, which runs on all common platforms including Windows and macOS. We offer a convenience script (objectbox-admin.sh) but it’s also simple enough to run it via plain Docker. See the docs for details, or get started by following this short tutorial.

Data Browser

The ObjectBox Admin Web App comprises a menu on the left (Data, Schema, Status, GraphQL…) and the corresponding content pane on the right-hand side.

ObjectBox Admin Web App (Data, Schema, Status, GraphQL...)

The data browser provides a table of objects of a specific type. By clicking on the Type we can select an entity type for viewing its entity objects.

WebAdmin_Data_Type

Next to the type selection is a small filter icon (the dashed triangle right of the type selection).

When selected, a query editor pops up that allows to filter data by adding a Property/Operator/Value expression.

ObjectBox Admin Filtering

When finished, click the check mark, and the data table gets updated with an active filter.

Data Filter

At the bottom, you will find a download link that exports the objects of the currently viewed box in JSON format.

DownloadDataAsJson

Schema Browser

You can get a detailed list of elements that make up an object type in the “Schema” pane.

Schema pane

In accordance with the “Data” pane, you can click on Type to select the schema of a specific entity type of your database.

Status

Base level database and ObjectBox Admin information can be viewed on the “Status” pane.

Status pane

GraphQL

The Docker-version of ObjectBox Admin offers a pane to query the database using GraphQL.

GraphQL Data Browser

What is an Edge Database, and why do you need one?

What is an Edge Database, and why do you need one?

Edge Databases – from trends to use cases

Data is decentralized. Cloud computing is centralized. Forcing the decentralized world into the centralized cloud topology is not only inefficient, but also economically, ecologically and socially wasteful – and sometimes simply impossible.

To drive digitization and extract value from decentralized data, we need to give the cloud an edge, or more precisely add Edge Computing. Edge computing is a decentralized topology for storing and processing data as close as possible to the data source, i.e., the place where the data is produced, at the edge of the network.

Valuable data is increasingly generated in a decentralized manner – outside traditional and centralized data centers and cloud environments. The dominance of centralized cloud computing approaches slows down digitization and the use of this existing decentralized data. Therefore, according to Gartner (2023) β€œEdge computing is integral to digital transformation”, and we need infrastructure technologies for the edge that enable developers to quickly and reliably work with decentralized edge data.

Edge Database (Foundation for Edge Data Management) is a new type of database that addresses these requirements. Developers need fast local data persistence and decentralized data flows (Data Sync) to implement edge solutions. Edge Databases solve these core edge functionalities out-of-the-box, allowing application developers to quickly implement edge solutions.

Megatrend to decentralized Edge Computing

By 2030, 30+ billion IoT devices will be creating ~4.6 trillion GB of data per day. The growing numbers of devices and data volume, variety, and velocity, as well as bandwidth infrastructure limitations, make it infeasible to store and process all data in a centralized cloud. On top, new use cases come with new requirements, a centralized cloud infrastructure cannot meet. For example, soft and hard response rate requirements, offline-functionality, and security and data protection regulations.

trends-driving-edge-computing

These trends accelerate the shift away from centralized cloud computing to a decentralized edge computing topology. Edge computing refers to decentralized data processing at the “edge” of the network. For example, in a car, on a machine, on a smartphone, or in a building. Hardware specifications do not capture the definition of an “edge device”. The crucial point is rather the decentralized use of data at, or as close as possible to, the data source.

Edge computing itself is not a technology but a topology, and according to McKinsey, one of the top growing trends in tech in 2021. The technologies needed to implement the edge computing topology are still inadequate. More specifically, there is a gap in basic β€œcore” edge technologies, so-called β€œsoftware infrastructure”. This gap is one of the main reasons for the failure of edge projects.

Needed: Infrastructure Software for Edge Computing

With computing shifting to the edge of the network, the needs of this decentralized topology become clear:

hugh performance db

Need for fast local data storage

β†’ i.e. a machine on the factory floor collects data on stiffness, friction, pressure points. There is limited space on the device, and typically no connection to the Internet. Even with an Internet connection, high data rates quickly push the available bandwidth, as well as associated networking / cloud costs, to the limit. To be able to use this data, it must be persisted in a structured manner at the edge, e.g. stored locally in a database.

feedback dialogue icon

Need for reliable on-device data flows

β†’ i.e. the car is an edge device consisting of many control units. Therefore, data must be stored on multiple control units. In order to access and use the data within several of the control units of the car, the data must be selectively synchronized between the devices. A centralized structure and thus a single point of failure is unthinkable.

data sync

Need for edge-to-edge-to-cloud data flows

β†’ i.e. in a manufacturing hall: Typically, you will find any number of diverse devices from sensors to brownfield to greenfield devices, and no internet connectivity. At the same time, there are diverse employee devices such as tablets or smartphones, as well as central PCs, and a cloud. To extract value from the data, it must be available in raw, aggregated, or summary form, in different places. This means it needs to be synchronized efficiently and selectively, with possible conflicts resolved.

types-of-data-on-edge-flexibility

Need for flexible edge data management

β†’ e.g. with the rise of IoT, time-series data have become common. However, time series data alone is usually not sufficient, and needs to be combined with other data structures (like objects) to add value. At the same time, a push to standardize data formats in industries (e.g. VSS in automotive or Umati in Industrial IoT) requires that the database supports flexible data structures.

Developing solutions without software infrastructure on an individual level is possible, but has many drawbacks:

Custom in-house implementations are cumbersome, slow, costly, and typically scale poorly. Oftentimes, applications or certain feature sets become unfeasible to deliver because of the lack of core software infrastructure. Legacy code and individual workarounds create problems over the lifetime of a product. Instead of a thriving ecosystem, only a few big players are able to implement edge solutions. Innovation and creativity are limited. An edge database is part of the solution and enables the entire edge ecosystem to build edge applications faster, cheaper and more efficiently.

lack-of-core-tech-for-the-edge

What is an Edge Database?

An Edge Database is a type of database specifically tailored to the unique requirements of the Edge Computing topology. Edge Databases run directly on-device, locally, and make it easy for app developers to access decentralized data from edge devices when and where needed. Using an Edge Database removes the burden of implementing ways to synchronize data, which is non-trivial, time-consuming, risky, and brings ongoing maintenance needs. Let’s look at this in more detail:

First, an Edge Database is optimized for resource efficiency (CPU, memory, …) and performance on resource-constrained devices (embedded devices, IoT, mobile). It has a small footprint of a few megabytes max. Traditional databases such as MySQL or MongoDB are too large and slow for typical edge devices, making them unsuitable for computing at the edge. Nevertheless, with integrations like the one between ObjectBox and MongoDB, developers can now combine ObjectBox’s on-device efficiency and offline-first capabilities of Edge Databases with MongoDB’s scalable cloud platform to enable seamless, bi-directional synchronization between the edge and the cloud.

An edge device without data flows to/from other devices is just a data island with very limited utility. Accordingly, an Edge Database must support the management of decentralized data flows. There is no more efficient way than at the database level. This ideally includes a range of conflict resolution strategies due to the decentralized and multi-directional structure of the Edge.Β 

Last not least, data security is of growing importance and data in motion needs to be protected. Data at rest is on a database level often protected by the OS and therefore less of a concern for most applications.Β 

 

What is an Edge Database?

When do you need an Edge Database?

Most IoT applications need to store and synchronize data. An Edge Database is always useful when functions / applications are planned that:

  • should work offline and independent of an internet connection
  • need to guarantee fast response times
  • work with a lot of, possibly high-frequency data
  • need to serve many devices at the same time
  • need historical data

In addition, developers also often decide to use an Edge Database to save time and nerves, or to be able to react quickly and flexibly to future requirements.

Edge Database Use Case Example in Manufacturing

Today, you can find everything from low-frequency brownfield devices to high-frequency greenfield devices on a factory floor. As a rule, the machine controllers in use are not designed to store or transmit data. They usually lack not only the functionality, but also the resources to support this. Therefore, additional edge devices are often needed to collect, analyze and interpret the huge amounts of data that each machine produces on site. For such an edge device, rapid data persistence and ingestion, and efficient data flow from edge-to-edge and edge-to-cloud are at the heart of value creation. The clear separation of machine control and edge data processing unit ensures that there is no risk of unintentional interference with the machine controller. An edge device with a powerful edge database can support multiple use cases on the shop floor today:

manufacturing-edge-computing-use-case

1. Operational efficiency

Process optimization along the line to increase quality and reduce damage. When the first machine in a production line uses a new batch of material, i.e. in sheet metal processing, one of the first steps is to cut a sheet to the required size. At this stage, the machine can already detect the differences in the metal compared to a previous batch (deviations are allowed within the DIN standard). With an Edge device this data can be evaluated, and the relevant information passed on to the next machine. With this data machines further down the line can avoid damage / breakpoints of the material.

2. Condition monitoring

Continuous machine condition monitoring reduces downtime and increases maintenance efficiency. A constant stream of high-frequency machine data is compared against the fingerprint of the machine. Any slight deviation is immediately detected and reported. Catching deviations early reduces down-times and costly repairs.

3. Historical Data

Historical data is stored for learning and training to optimize the production line. With an Edge Database, the data is persisted and thus available in the event of faulty behavior. In case of an error, the data preceding the incident can be analyzed and used to find the causes and predict, or even avoid, such an error in the future. Chances are that “fuzzy expert knowledge” already available at the production site can be translated into deterministic rules when tested with these data sets.

The future of Edge DatabasesΒ 

Edge computing provides numerous benefits and enables many applications and functionalities that are only possible with edge computing. However, only a few (usually large) players have been able to create value in edge computing projects, gaining competitive advantages. One reason is a lack of basic edge software. A thriving edge ecosystem necessitates edge software infrastructure that addresses the fundamental recurring needs of edge projects. Edge databases are a critical component in the development of such an ecosystem.

Looking ahead, the emergence of on-device vector databases, coupled with small language models (SLMs), is transforming the landscape of AI applications. These technologies enable AI apps to run directly on edge devices, providing long-term memory, improving performance, and significantly reducing resource consumption. By processing data locally, they eliminate the need for constant cloud connectivity, enhancing privacy and efficiency. Companies like Apple have already embraced on-device AI (Apple Intelligence), showcasing its potential to deliver advanced functionalities seamlessly. This shift represents a game-changer, making AI more sustainable, scalable, and integrated into everyday use.

How to start using ObjectBox Database in Flutter

How to start using ObjectBox Database in Flutter

This tutorial will help you get started with the ObjectBox Flutter Database. We will create a simple task-list app using all ObjectBox CRUD operations (Create, Read, Update, Delete). Additionally, we will support adding a tag to each task by setting up a to-one relation between tasks and tags. The pure Dart ObjectBox API is very easy to use, as you will see by going through the steps outlined below.Β 

A couple of useful links:

About the app

Users can enter a new task, choose which tag to apply and add the task. All added tasks are displayed as a checklist with the associated tag. Users can mark a task as finished by ticking its checkbox and delete it by swiping it away.Β 

Each task entry also shows the date when it was created or finished, depending on the state of the task.

Tasklist example app built with ObjectBox database in Flutter

How to start using the ObjectBox Database in your Flutter app

Add the library

Please refer to the Getting Started page for up-to-date information about adding the ObjectBox dependencies to your project.

Create a model file

ObjectBox is an object-oriented non-relational (NoSQL) database. First, we need to tell the database which entities to store. We can do this by defining a model and then using the build_runner to generate the binding code. The model is defined by writing Dart classes and annotating them.Β Β Β Β 

Create a model file (e.g. model.dart), where we want to define two entities: one for task tags and one for tasks. These are just Dart classes with the @Entity annotation. Each entity must have an ID property of type int, which serves as the unique identifier. When this is called β€œid”, the property is recognized automatically but if you want to use a different name, annotate it with β€œ@Id()”. In the Tag class, we also create a String property for the tag name. Here is how the model will look. Don’t worry about the objectbox.g.dart import for now – this file will be generated later.

Additional properties of our Task entity include a String for the task’s text and two DateTime properties for the date when a task was created and finished. Then we also define a to-one relation between Tasks and Tags. This is needed so that one can assign a tag to each task created within the app. We’ll come back to how relations work at the end of this tutorial.

Generate binding code

Once our model is done, we generate the ObjectBox binding code by running flutter pub run build_runner build. This will create the objectbox.g.dart file from the import above. You will need to do this every time you update the model (e.g. by adding or removing an entity or a property), and ObjectBox will take care of the change. However, in cases like entity renaming, you will need to provide ObjectBox with more information. Read more about data model updates in the ObjectBox docs.

Create a Store

Store represents an ObjectBox database and works together with Boxes to allow getting and putting. A Box instance gives you access to objects of a particular type. One would typically create one Store for their app and a number of Boxes that depends on the number of entities they want to store in the database.

In a separate file, e.g. objectbox.dart, we define the ObjectBox class that will help us create the store. We only need a single database store where we get two Boxes – one for each object type. Let’s call these taskBox and tagBox.

So that our app can always display the current list of tasks without the need to actively refresh it, we create a data stream. Within ObjectBox, we can stream data using queries. We query all tasks by using taskBox.query() and order them by date created in a descending order: order(Task_.dateCreated, flags: Order.descending). Then we use the watch() method to create a stream.

Finally, we define the create() method that will create an instance of ObjectBox to use in our app.

Open the store

Now we can initialise the store in our app’s main() function. Do this by calling the create() method of the ObjectBox class.

CRUD operations

CREATE – Put a new Task or Tag into the Store

In the homepage state subclass of main.dart, we define the methods for adding new tasks and tags. Start by creating a task using the input controller. Then, set a tag we want to relate to this task by calling tag.target(). Now we only need to put the new Task object in its Box.

READ – Get all tag names

To get all tag names, we call getAll() on our tagBox. This will return a list with all tags. If you want to read just a single object, call the get(id) method to get only the desired single object back. For a range of objects, use getMany(), passing a list of ids to it.

Another way of reading data is by using queries. In the β€œCreate a Store” section above, we created a task stream with the help of a query builder. There we just needed all tasks, so no criteria was specified. But generally, one can specify custom criteria to obtain a list of objects matching the needs. Learn more about how to use queries using the ObjectBox Query Docs.

Β 

DELETE – remove tasks by swiping

To remove objects from the database, we add a dismissible Flutter widget. Inside the setState method of the onDismissed property, we simply use the ObjectBox remove() operation with the corresponding task id.

UPDATE – Updating the date when Task was finishedΒ 

Our app prints all tasks as a list with checkboxes. Each task’s finished date is initially set to null. We want the finished date of a task to update when the user marks the task as done. The non-null finished date therefore will act as an indicator that the task is finished. Let’s do this inside the setState() method of the onChanged property of our Checkbox class. Set the dateFinished to DateTime.now() if it was null when the checkbox value was changed, and set back to null otherwise.Β 

Relations

Remember we initialised a ToOne relation in the very first section and planned to come back to this at the end? Now that we have covered all CRUD operations, we can come back to discussing those.

Relations allow us to build references between objects. They have a direction: a source object references a target object. There are three types of relations:

  • to-one relations have one target object, as used above;
  • one-to-many relations can have multiple target objects, but each target only has one source, e.g. we could add a backlink (one-to-many) to Tag in our example to find out all tasks with a specific tag;
  • many-to-many relations involve targets that can have multiple sources, e.g. to improve our example app by supporting multiple tags per task, we could replace the to-one with a many-to-many relation.

Read about relations in more detail and learn how to use them with the help of the ObjectBox Relations Docs or our video tutorial.

How to use relations

When listing all tasks, we might want to include each task’s tag next to the task name. The relations are already initialised (see the β€œCreate a model file” section). Now we need to read the tag of each task we want to list. So, inside the Text widget that displays the task name, we use tasks[index].tag.target?.name to print the name of the corresponding tag.

Build your own Flutter app with the ObjectBox Database

Now you have all the tools needed to build your own version of the task-list app with tags. The setup we described is rather minimal, so that anyone can get started easily. However, this gives you lots of room for improvement. For example, you could replace the existing to-one relation with a to-many, allowing users to add more than one tag per task. Or you can add task-list filtering and/or sorting functionality using different queries. The possibilities are truly endless.

We’d like to learn more about the creative ways to use the ObjectBox Database in Flutter you came up with! Let us know via Twitter or email.

Cross platform Data Sync: a simple example

Cross platform Data Sync: a simple example

Cross platform data sync can be simple: In this tutorial we will show you how you can easily sync data across devices.

Built for fast and effortless data access on and across embedded devices from Mobile to IoT, ObjectBox keeps data in sync between devices for you, with robust offline sync capabilities to handle network interruptions. The Database and Data Snyc works across platforms (iOS, Android, Linux, Rasbian, Windows, MacOS) and supports a variety of languages with easy native APIs (Swift, Java, Kotlin, C / C++, Flutter / Dart, Golang), providing seamless offline-first data sync across devices, regardless of the platform..

For example, you can sync between an Industrial IoT sensor app in Go and a C++ monitoring application – and a mobile Android app written in Kotlin or Java – and of course an iOS app written in Swift – and… you get the drift πŸ˜‰

ObjectBox is a high-performance embedded database for Edge Computing with integrated Data Sync. The ObjectBox database is quick to set up and free and easy to use. Our powerful and intuitive APIs are a great match for multiplatform development environments.

Syncing data across devices – a task-list app example

In this tutorial, we are going to sync data across three instances of an example task-list app (written in C++, Go and Java).

With the task-list app, users can create simple text-based tasks and mark them as done. It stores tasks together with their creation dates. There is also a parameter to store the date when the task was completed. It acts as a filter for users to only see unfinished tasks.Β 

This app is a standard cross platform ObjectBox example that is available for all language bindings. Here are the repositories of each example app that we will be looking at today:

Overview of the example codeΒ 

In this section, we’ll quickly review how the the task-list example app uses ObjectBox Sync. For a more detailed description, check out the Sync docs. If you want to see how each of these steps were incorporated into the example code, go to the next section.

Note: The basic use of the database and its sync features is the same for all programming languages. If you haven’t used the ObjectBox DB yet, please refer to the corresponding documentation: C/C++ Docs, Java/Kotlin/Dart Docs, Go Docs, Swift Docs.

For sync to work in any app, we generally only need four things:

  1. The sync-enabled library β€” this is not the same as the general ObjectBox library and has to be downloaded separately.
  2. Database objects enabled for sync β€” for this we need include the sync annotation in the ObjectBox schema file.
  3. ObjectBox Sync Server β€” please apply for a free Sync Trial here to get your own copy of the Sync Server (available for Linux and Docker). Note that this will only have to be started once and in this tutorial we’ll show you how to run the server on Linux. If you are using Docker, follow the steps outlined here.
  4. Start a Sync Client in the app β€” as one can see from the Sync Client docs, creating and starting a sync client is just a matter of a couple of lines of code.

Important: When syncing between different apps, please make sure that the UIDs in the model JSON file (e.g. objectbox-default.json) are the same everywhere.

    How to run the examples

    Here you’ll find requirements and step-by-step guides for running the task-list example app in each of the three languages.

    C++ example app

    Requirements

    New to C++? Check out our beginner C++ ObjectBox installation tutorial.

    • WSL Ubuntu
    • CMake
    • Git
    • C++
    • Clang

      Step-by-step guide

      1.Start by creating a CMakelists.txt file:

      Now configure and build the project via CMake: Configure (Clang), CMake: Build.

      2. Sync-enabled objects: note the first line in tasklist.fbs.

      3. [if not running a server already] Start the ObjectBox Sync Server on Linux by runningΒ ./sync-server --model build/_deps/objectbox-src/examples/cpp-gen/objectbox-model.json --unsecured-no-authentication

      where sync-server is the path to your sync server executable. You can find more information about the server in the Sync Server docs.

      4. Sync Client: launch [objectbox-c-examples-cpp-gen-sync], and the Sync Client will start automatically. You can see how it was implemented in main.cpp.

      As this is just an example, we opted for no authentication to make things simple. This is not what you would use in production. We currently offer two authentication methods: shared secret and Google Sign-In. Here is the relevant SyncΒ docs section on authentication optionsΒ that explains how to use these.

      5. Let’s add a first task, called β€œtask-cpp” (new task-cpp-1), to check if our C++ app syncs correctly. The output should look like this:

      Output of the C++ tasklist example app, showing a newly added task

      6. You can finally open the Admin UI to check if the task appears there. This is most easily done by opening http://127.0.0.1:9980/ in any web browser. For a more detailed description of what this can do, check out the Admin UI docs.

      Go example app

      Requirements

      • WSL Ubuntu
      • Go (see how to configure it for VS Code here)
      • Git

      Step-by-step guide

      1. First, clone the objectbox-goΒ repository to your VS Code project. Make sure the current directory is objectbox-go.

      2. Sync-enabled objects. There are two versions of the task-list example: with and without sync. To run the one with sync, we need to enable our Task object for syncing. To do this, simply put the sync annotation on a new line in examples/tasks/internal/model/task.go:

      Then run the generator: go generate examples/tasks/internal/model/task.go to update the schema.

      3. [if not running a server already] Now start the ObjectBox Sync Server: ./sync-server --model=examples/tasks/internal/model/objectbox-model.json --unsecured-no-authentication,

      where sync-server is the path to your sync server file. You can find more information about the server in theΒ Sync Server docs.

      4. Run go run examples/tasks/main.go. The Sync Client will start within the app; check main.go to see how this was implemented.

      As this is just an example, we opted for no authentication to make things simple. This is not what you would use in production. We currently offer two authentication methods: shared secret and Google Sign-In. Here is the relevant SyncΒ docs section on authentication optionsΒ that explains how to use these.

      5. Now we can add our first task (new task-go) – if it synced correctly, you should already see that from the output of the app. In particular, there will be a message from the change listener (“received 1 changes”):

      Output of the Go task-list example app after adding a first task

      6. Lastly, open the Admin UI to check if the task appears there. This is most easily done by opening http://127.0.0.1:9980/ in any web browser. For a more detailed description of what this can do, check out the Admin UI docs.

      Admin UI showing a task created with the Go example app

      Java (Android) example app

      Requirements

      • Java
      • Android Studio

      Step-by-step guide

        1. First of all, open Android Studio and clone the objectbox-examples repository via File β†’ New β†’ Project from Version Control. Use this URL: https://github.com/objectbox/objectbox-examples.git
        2. Sync-enabled objects:Β check out Task.java to see how this was done (note the @Sync annotation).
        3. [if not running a server already] Start the ObjectBox Sync Server:Β 

      ./sync-server --model android-app-sync/objectbox-models/default.json --unsecured-no-authentication,

      where sync-server is the path to your sync server file. You can find more information about the server in theΒ Sync Server docs.

      1. Now you can run β€œandroid-app-sync” on a device of your choice. The Sync Client will start in the app.Β 

      As this is just an example, we opted for no authentication to make things simple. This is not what you would use in production. We currently offer two authentication methods: shared secret and Google Sign-In (only for Java, Kotlin, Dart, C & Go). Here is the relevant SyncΒ docs section on authentication optionsΒ that explains how to use these.

      5. Add a new task called β€œtask-java”.

      6. Finally, open the Admin UI to check if the task appears there. This is most easily done by opening http://127.0.0.1:9980/ in any web browser. For a more detailed description of what this can do, check out the Admin UI docs.

      Next Steps

      How easy was that? cool Now that you’ve run your first ObjectBox Sync example, why not build something yourself? Use any combination of the supported languages to build your own cross platform app.

      We’re eager to see your use case examples! Don’t hesitate to share your results with us by posting on Social Media and tagging @objectbox_io, or simply sending us an email on contact[at]objectbox.io.Β 

       

      If you want to learn more about how ObjectBox can be used in IoT, here is an overview of different use cases.Β 

      ObjectBox Database Java 3.1 – Flex type

      ObjectBox Database Java 3.1 – Flex type

      We are happy to announce version 3.1 of ObjectBox for Java and Kotlin. The major feature of this version is the new Flex type. For a long time, ObjectBox worked on rigid data schemas, and we think that this is a good thing. Knowing what your data looks like is a feature – similar to programming languages that are statically typed. Fixed schemas make data handling more predictable and robust. Nevertheless, sometimes there are use cases which require flexible data structures. ObjectBox 3.1 allows exactly this.

      Flex properties

      Expanding on the string and flexible map support in 3.0.0, this release adds support for Flex properties where the type must not be known at compile time. To add a Flex property to an entity use Object in Java and Any? in Kotlin. Then at runtime store any of the supported types.

      For example, assume a customer entity with a tag property:

      Then set a String tag on one customer, and an Integer tag on another customer and just put them:

      When getting the customer from its box the original type is restored. For simplicity the below example just casts the tag to the expected type:

      A Flex property can be not justString or Integer. Supported types are all integers (Byte, Short, Integer, Long), floating point numbers (Float, Double), String and byte arrays.

      It can also hold a List<Object> or a Map<String, Object> of those types. Lists and maps can be nested.

      Behind the scenes Flex properties use a FlexBuffer converter to store the property value, so some limitations apply. See the FlexObjectConverter class documentation for details.

      Query for map keys and values

      If the Flex property contains integers or strings, or a list or map of those types, it’s also possible to do queries. For example, take this customer entity with a properties String to String map:

      Why is properties not of type Object? ObjectBox supports using Map<String, String> (or Map<String, Object>) directly and will still create a Flex property behind the scenes.

      Then put a customer with a premium property:

      To query for any customers that have a premium key in their properties map, use the containsElement condition:

      Or to only match customers where the map key has a specific value, here a specific premium tier, use the containsKeyValue condition:

      What’s next?

      ObjectBox database is free to use. Check out our docs and this video tutorial to get started today.

      We strive to bring joy to mobile developers and appreciate all kinds feedback, both positive and negative. You can always raise an issue on GitHub or post a question on Stackoverflow. Otherwise, star the ObjectBoxΒ  Java database GitHub repo and up-vote the features you’d like to see in the next release.

       

      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.