When you save data in your application, you will need to think about the structure of the data, and how it should be represented in the Editor. That's where defining types and fields is extremely important. The explanations below for the different concepts will use the hypothetical case of a car rental marketplace, that enables users to lend their car to other users.
The different types of data ("data types") are the most high-level concept you define when you build a data-driven application. They let you describe an entry in the database as a XX. In our marketplace case, the different data types will include a 'Car', a 'Booking', a 'Review'. Defining these types is the first step to describe what the database will contain, before defining how to describe these items.
A built-in data type that exists in any Bubble application is the User type. In our marketplace example, users will be interacting with each others, and therefore need to exist in the database, described by their email. This data type is particular and have specific properties, a section below covers it in details.
As soon as a data type exists in Bubble, a list of things of that type also becomes possible. If a data type is a 'car', a 'list of cars' will be another type that you can work with in Bubble, display in a repeating group, etc.
Fields are the way you will define how an entry of a given data type should be described. Effectively, this will where you will save the data of a given entry. For instance, a 'car' (that has the type 'car', as defined above), will have a 'brand', a 'mileage', a 'color', a 'picture', etc. Defining this fields will let you save the right data at the right place, and display it in your application.
When you create a field on a data type (the User Interface to do this will be covered later in this chapter), you have to pick a type for the that field. Most fields will use one of the Bubble-built-in field types:
- text: used to represent a text (a chain of characters)
- number: used to represent a number, with our without decimals
- yes/no: used to represent a value that is yes, or no (boolean in traditional programming languages)
- date: used to represent a specific date, i.e. a date and a time
- geographic address: used to represent an address (on a map)
- image, file
- number interval
- date interval
For instance, in our base example, a car will have a 'name' (field) of type text, an 'image' of type 'image', a 'price' of type number.
The field type will have important consequences on how you can use the data when you're building your app. For instance, to do some operations. Fields of type text can be concatenated or truncated, numbers can be multiplied, etc. Addresses, can be shown on a map, etc. In order to calculate 10% of a 'car', we'll need the price to be a field of type 'number'. Fields' types will also be important to sort entries in a list. If we want to sort cars by price, the field has to be a number.
A field can also have a type defined by yourself (or the user type) - in other words, a given field's type can actually be a data type. These types, called composite types, are a way to associate two entries in the database. For instance, a car is going to have an owner, of type user.
A thing, in Bubble, is an entry in the database. For instance, a specific car created by a user in our example. This concept is defined for convenience to name database entries. In the Bubble editor, you'll see in many places mentions to 'things', and as soon as you define a type of content that can be applied in the context, 'thing' will be replaced by the type name, for instance 'car'.
By design, Bubble adds a few fields to each type. These fields are the 'Created Date' and the 'Modified Date' of type date. For things that aren't users, a third field is 'Creator', which is of field type User. For each thing that isn't a User, this field will link it to the user that was logged in when the thing was created (see below the few actions that let you create things).
Each thing in Bubble gets a unique ID assigned when it gets created. Using this field isn't common, but in some cases, if you need a way to uniquely identify a thing, you can use the 'unique id' field.
Instead of these fields yourself, you can rely on Bubble's data engine to create these fields, assign the right data when a thing is created, and use that data where you need it.
Container elements (and a few elements in the Visual Element sections, such as a map element) have a 'type of content' field. This property lets you define what kind of data (or what type of things) an element will display. For instance, a repeating group can display a list of 'cars'. Defining this at the repeating group level is very important as it lets you access the different fields of the given type inside the container. For instance, if the repeating group displays a list of cars, you may want to add a text in the first cell and define the caption of the text as 'Current cell's car's name'. Defining the type of content will let Bubble know which fields are available in the context of each container.
If you use some plugins that connect to external APIs in your app, it is very likely these APIs will add some data types to your application. For instance, if you're connecting to Twitter, a type of data that Twitter returns if you make some calls to them is a 'Tweet'. These data types are quite similar to the custom data types defined above, as they can describe things and have some fields. In many places of the Bubble Editor, you will be able to use them similarly to above. For instance, if you're using a repeating group to display a list, you will be able to pick 'Tweet' as type of content. However, the main difference is that you cannot create things of this type (you cannot create a thing of type 'Tweet'), and you cannot modify them.
There are two main ways to create data types and fields in Bubble. You can either do this in the Data Tab, as described in the relevant section or on the fly when working with actions that creates or modifies a thing. Both paths have the same effect on your data structure, and mostly depend on how you think about your data. You can either do this starting from the data structure, before you start adding workflows to your app, in which case the Data Tab is more natural, or you can define the different fields you need to describe a car when you are actually using an action to create such a car.
The Issue Checker helps you identify inconsistencies in your application. Many inconsistencies that you will have to fix when designing your application will be type inconsistencies. When an element or an action is expecting a given type, and you're using an expression to define the data that leads to another type, the Issue Checker will flag this as an issue to fix. Fixing these issues is very important to get the expected behavior of your application in run mode.
For instance, let's say you are using a group whose type of content is a 'car'. This means the group (and the elements inside) will be referring to a particular car to display its picture, name, price, etc,. in run mode. Now let's say you have an action that displays data in that group (in other words, that define which thing should be displayed in the group). This action should display a thing of type 'car'. If you design your action in a way that in run mode, the thing you're trying to display in the group is evaluated as a 'user', there will be a type inconsistency. The Issue Checker will catch this in edit mode.
Such type inconsistencies can also happen with field types. For instance, if you are using a 'Charge the current user' action to charge a user's credit card, one of the field is going to be the 'amount'. This field, naturally, should be a number. If you use a dynamic expression to define this amount, and if it evaluates to a text or an address, the Issue Checker will flag this as an issue to resolve.