Parse Datatypes on Flutter
Introduction
In this guide you will learn about the Parse Datatypes using Flutter. You will read and save the Parse Datatythis on Back4App from a Flutter App.
Storing data on Parse is built around the ParseObject
. Each ParseObject
contains key-value pairs of JSON-compatible data. This data is schemaless, which means that you don’t need to specify ahead of time what keys exist on each ParseObject
. You can set whatever key-value pairs you want, and our backend will store them. For example, let’s say you’re tracking high scores for a game. A single ParseObject
could contain:
1
score: 1337, playerName: "Sean Plott", cheatMode: false
Keys must be alphanumeric strings, and values can be:
String
Number
(primitive numeric values such asint
,double
)Bool
DateTime
(contains a UTC timestamp stored in ISO 8601 format with millisecond precision: YYYY-MM-DDTHH:MM:SS.MMMZ.)Map
Null
List
(any type of data)File
Pointer
(association with another ParseObject: 1 to N)Relation
(association with another ParseObject: N to N)Geopoint
(store latitude and longitude coordinate)
Each ParseObject
has a class name that you can use to distinguish different sorts of data. For example, we could call the high score object a GameScore
. There are also a few fields you don’t need to specify that are provided as a convenience:
objectId
is a unique identifier for each saved object.createdAt
andupdatedAt
represent the time that each object was created and last modified in the cloud.
Each of these fields is automatically filled in by Back4app at the moment you save a new ParseObject
.
We recommend you
NameYourClassesLikeThis
andnameYourKeysLikeThis
, just to keep your code looking pretty.
Prerequisites
To complete this tutorial, you will need:
- Flutter version 2.2.x or later
- Android Studio or VS Code installed (with Plugins Dart and Flutter)
- An app created on Back4App.
- Note: Follow the New Parse App Tutorial to learn how to create a Parse App on Back4App.
- An Flutter app connected to Back4app.
- Note: Follow the Install Parse SDK on Flutter project to create an Flutter Project connected to Back4App.
- A device (or virtual device) running Android or iOS.
Understanding our App
To better understand Back4app in Flutter, we will create an application that will save and retrieve records with the main types of data supported. We won’t explain the Flutter application code once this guide’s primary focus is using the Flutter with Parse. The data types Pointer
, Relation
, File
, Geopoint
will be covered later in specific guides.
Let’s get started!
In the following steps, you will build an application that will save and read the data in the Back4App database.
Step 1 - Create App Template
Open your Flutter project from the previous guide Flutter plugin for Parse Server.
Go to the main.dart
file, clean up all the code, and replace it with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import 'package:flutter/material.dart';
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final keyApplicationId = 'YOUR_APP_ID_HERE';
final keyClientKey = 'YOUR_CLIENT_KEY_HERE';
final keyParseServerUrl = 'https://parseapi.back4app.com';
await Parse().initialize(keyApplicationId, keyParseServerUrl,
clientKey: keyClientKey, debug: true);
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
String objectId = '';
void showMessage(String message) {
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text(message)));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Parse Data Types"),
backgroundColor: Colors.blueAccent,
centerTitle: true,
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 200,
child: Image.network(
'https://blog.back4app.com/wp-content/uploads/2017/11/logo-b4a-1-768x175-1.png'),
),
SizedBox(
height: 16,
),
ElevatedButton(onPressed: doSaveData, child: Text('Save Data')),
ElevatedButton(onPressed: doReadData, child: Text('Read Data')),
ElevatedButton(
onPressed: doUpdateData, child: Text('Update Data'))
],
),
),
));
}
void doSaveData() async {
}
void doReadData() async {
}
void doUpdateData() async {
}
}
Note:
When debug
parameter in function Parse().initialize
is true
, allows displaying Parse API calls on the console. This configuration can assist in debugging the code. It is advisable to disable debug in the release version.
Step 2 - Connect Template to Back4app Project
Find your Application Id and Client Key credentials navigating to your app Dashboard at Back4App Website.
Update your code in main.dart
with the values of your project’s ApplicationId and ClientKey in Back4app.
- keyApplicationId = App Id
- keyClientKey = Client Key
Run the project, and the app will load as shown in the image.
Step 3 - Code for Save Object
The create function will create a new object in Back4app database. Search for the function doSaveData
in file main.dart
, and insert the code below inside the doSaveData
function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var parseObject = ParseObject("DataTypes")
..set("stringField", "String")
..set("doubleField", 1.5)
..set("intField", 2)
..set("boolField", true)
..set("dateField", DateTime.now())
..set("jsonField", {"field1": "value1", "field2": "value2"})
..set("listStringField", ["a", "b", "c", "d"])
..set("listIntField", [0, 1, 2, 3, 4])
..set("listBoolField", [false, true, false])
..set("listJsonField", [
{"field1": "value1", "field2": "value2"},
{"field1": "value1", "field2": "value2"}
]);
final ParseResponse parseResponse = await parseObject.save();
if (parseResponse.success) {
objectId = (parseResponse.results!.first as ParseObject).objectId!;
showMessage('Object created: $objectId');
} else {
showMessage('Object created with failed: ${parseResponse.error.toString()}');
}
To build this function, follow these steps:
- Make a new instance of the Parse
DataTypes
class with the commandParseObject("DataTypes")
. - Use the
set
function to set the parameters for this object. - Call the
save
function inParseObject
, which will effectively register the object to your database in the Back4app Dashboard. - Display a message with the
objectId
of the saved object.
To test it, click on the
Run
button in Android Studio/VSCode.
Click on theSave Data
button.
To confirm that the new object is in the database, you can access theBack4app Dashboard
or thedoReadData
function code.
Step 4 - Code for Read Object
The read
function is responsible for querying the database and returning the object created in doSaveData
function. Search for the function doReadData
in the file main.dart
, then insert the code below inside doReadData
function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (objectId.isEmpty) {
showMessage('None objectId. Click button Save Date before.');
return;
}
QueryBuilder<ParseObject> queryUsers =
QueryBuilder<ParseObject>(ParseObject('DataTypes'))
..whereEqualTo('objectId', objectId);
final ParseResponse parseResponse = await queryUsers.query();
if (parseResponse.success && parseResponse.results != null) {
final object = (parseResponse.results!.first) as ParseObject;
print('stringField: ${object.get<String>('stringField')}');
print('stringField: ${object.get<String>('stringField')}');
print('doubleField: ${object.get<double>('doubleField')}');
print('intField: ${object.get<int>('intField')}');
print('boolField: ${object.get<bool>('boolField')}');
print('dateField: ${object.get<DateTime>('dateField')}');
print('jsonField: ${object.get<Map<String, dynamic>>('jsonField')}');
print('listStringField: ${object.get<List>('listStringField')}');
print('listNumberField: ${object.get<List>('listNumberField')}');
print('listIntField: ${object.get<List>('listIntField')}');
print('listBoolField: ${object.get<List>('listBoolField')}');
print('listJsonField: ${object.get<List>('listJsonField')}');
}
To build this function, follow these steps:
- Create an instance of
ParseQuery
object forDataTypes
class. Insert a condition in the query, to search for the object created in thedoSaveData
function using the value of theobjectId
. - Do a Query’s search method using
query()
method. - If the operations succeed, one object
DataTypes
will be returned. - To access the values of the fields of our ParseObject use the
get
method, informing the data type.
To test it, click on the
Run
button in Android Studio/VSCode.
First, click on theSave Data
button e later click onRead Data
button.
Check the query result on the console.
Step 4 - Code for Update Object and Special Methods
The update
function is responsible for updating data in the object created on the doSaveData
function. Search for the function doUpdateData
in the file main.dart
, and insert the code below inside the doUpdateData
function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (objectId.isEmpty) {
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(
SnackBar(content: Text('None objectId. Click Save before.')));
return;
}
final parseObject = ParseObject("DataTypes")
..objectId = objectId
..set("intField", 3)
..set("listStringField", ["a", "b", "c", "d", "e"]);
final ParseResponse parseResponse = await parseObject.save();
if (parseResponse.success) {
showMessage('Object updated: $objectId');
} else {
showMessage('Object updated with failed: ${parseResponse.error.toString()}');
}
To build this function, follow these steps:
- Make a new instance of the Parse
DataTypes
class with the commandParseObject("DataTypes")
. - Use the
set
function to defineobjectId
of the object that we want to update and the field that we want to update - Call the
save
function inParseObject
, which will effectively register the object to your database in the Back4app Dashboard. - Display a message with the
objectId
of the updated object.
To test it, click on the
Run
button in Android Studio/VSCode.
First, click on theSave Data
button e later click onUpdate Data
button.
To confirm that the updated object is in the database, you can access theBack4app Dashboard
or you can execute thedoReadData
function.
Step 5 - Using Counters
The above example contains a common use case. The intField
field can be a counter that we’ll need to update continually. The above solution works, but it’s cumbersome and can lead to problems if you have multiple clients trying to update the same counter. Parse provides methods that atomically increment (or decrement) any number field to help with storing counter-type data. So, the same update can be rewritten as:
1
2
3
final parseObject = ParseObject("DataTypes")
..objectId = objectId
..setIncrement("intField", 1);
To decrement:
1
2
3
final parseObject = ParseObject("DataTypes")
..objectId = objectId
..setDecrement("intField", 1);
Step 6 - Using Lists
Parse also provides methods to help in storing list data. There are three operations that can be used to change a list field atomically:
setAdd
andsetAddAll
: append the given objects to the end of an array field.setAddUnique
andsetAddAllUnique
: add only the given objects which aren’t already contained in an array field to that field. The position of the insert is not guaranteed.remove
andremoveAll
: removes all instances of the given objects from an array field.
Step 6.1 - Examples with setAdd
and setAddAll
listStringField
has the value:
1
["a","b","c","d","e","f","g","g"]
Running the code below:
1
2
3
4
final parseObject = ParseObject("DataTypes")
..objectId = objectId
..setAdd("listStringField", "e");
await parseObject.save();
1
2
3
4
final parseObject = ParseObject("DataTypes")
..objectId = objectId
..setAddAll("listStringField", ["e", "f", "g", "g"]);
await parseObject.save();
After this command the result of the stringList
field will be:
1
["a","b","c","d","e","e","f","g","g"]
Step 6.2 - Examples with setAddUnique
and setAddAllUnique
listStringField
has the value:
1
["a","b","c","d","e"]
Running the code below:
1
2
3
4
final parseObject = ParseObject("DataTypes")
..objectId = objectId
.. setAddUnique("listStringField", "e");
await parseObject.save();
1
2
3
4
final parseObject = ParseObject("DataTypes")
..objectId = objectId
.. setAddAllUnique("listStringField", ["c", "d", "e", "f"]);
await parseObject.save();
After this command the result of the stringList
field will be:
1
["a","b","c","d","e","f"]
No values were repeated.
Step 6.3 - Examples with remove
and removeAll
listStringField
has the value:
1
["a","b","c","d","e","f"]
Running the code below:
1
2
3
4
final parseObject = ParseObject("DataTypes")
..objectId = objectId
.. setRemove("listStringField", "f");
await parseObject.save();
1
2
3
4
final parseObject = ParseObject("DataTypes")
..objectId = objectId
.. setRemoveAll("listStringField", ["c", "d", "e", "f"]);
await parseObject.save();
After this command the result of the stringList
field will be:
1
["a","b"]
Note that it is not currently possible to atomically add and remove items from an array in the same save. You will have to call the save for every different array operation you want to perform separately.
Step 7 - Remove field from ParseObject
You can delete a single field from an object by using the unset
operation:
1
2
final parseObject = ParseObject("DataTypes")
..unset("stringField");
It’s done!
At this point, you learned about the Datatypes available on Parse Server and used them through a Flutter app. You learned how to read and save this data, special functions and learned a little more about ParseObject
.