Relational Queries on Android
Introduction
In this guide, you will perform relational queries in Parse
and implement an Android
app using these queries. You will learn how to set up and query realistic data using Back4App
and Android
.
This tutorial uses an app created in Android Studio Arctic Fox -2020.3.1 with compileSdk = 30
, minSdk = 23
and targetSdk = 30
At any time, you can access the complete Project via our GitHub repositories.
Goal
Query relational data stored on Back4App
from an Android
App.
Here is a preview of what we are gonna achieve:

Prerequisites
To complete this tutorial, we need:
- Android Studio.
- An app created on Back4App.
- Note: Follow the New Parse App tutorial to learn how to create a Parse App on Back4App.
- An android app connected to Back4App.
- Note: Follow the Install Parse SDK tutorial to create an Android Studio Project connected to Back4App.
- A device (or virtual device) running Android 4.1 (Jelly Bean) or newer.
Let’s get started!
Before next steps, we need to connect Back4App
to our application. You should save the appId
and clientKey
from the Back4App
to string.xml
file and then init Parse
in our App.java
or App.kt
file. Follow the New Parse App tutorial if you don’t know how to init Parse
to your app. You can also download the projects we shared the github and edit only the appId
and clientKey
parts according to you.
Download the Project Template from Github
Step 1 - Save some data on Back4App
In this step, we will create a Class with the JS Console and Javascript codes provided by Parse
and we will create queries for this Class.
Let’s create an assortment of classes, which will be the target of our queries in this guide. The classes are: Author
, Book
, Publisher
and BookStore
, in which Book
has a 1:N relation with Publisher
and N:N with Author
, and BookStore
has an N:N relation with Book
.
On Parse JS Console is possible to run JavaScript code directly, querying and updating your application database contents using the JS SDK commands. Run the code below from your JS Console and insert the data on Back4App. Here is how the JS console looks like in your dashboard:
Go ahead and create the classes with the following example content:
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
// Add objects and create tables
// Authors
const AuthorA = new Parse.Object('Author');
AuthorA.set('name', 'Aaron Writer');
await AuthorA.save();
const AuthorB = new Parse.Object('Author');
AuthorB.set('name', 'Beatrice Novelist');
await AuthorB.save();
const AuthorC = new Parse.Object('Author');
AuthorC.set('name', 'Casey Columnist');
await AuthorC.save();
// Publishers
const PublisherA = new Parse.Object('Publisher');
PublisherA.set('name', 'Acacia Publishings');
await PublisherA.save();
const PublisherB = new Parse.Object('Publisher');
PublisherB.set('name', 'Birch Distributions');
await PublisherB.save();
// Books
const BookA = new Parse.Object('Book');
BookA.set('title', 'A Love Story');
BookA.set('publisher', PublisherA);
BookA.set('publishingDate', new Date('05/07/1998'));
const BookARelation = BookA.relation("authors");
BookARelation.add(AuthorA);
await BookA.save();
const BookB = new Parse.Object('Book');
BookB.set('title', 'Benevolent Elves');
BookB.set('publisher', PublisherB);
BookB.set('publishingDate', new Date('11/31/2008'));
const BookBRelation = BookB.relation("authors");
BookBRelation.add(AuthorB);
await BookB.save();
const BookC = new Parse.Object('Book');
BookC.set('title', 'Can You Believe It?');
BookC.set('publisher', PublisherB);
BookC.set('publishingDate', new Date('08/21/2018'));
const BookCRelation = BookC.relation("authors");
BookCRelation.add(AuthorA);
BookCRelation.add(AuthorC);
await BookC.save();
// BookStore
const BookStoreA = new Parse.Object('BookStore');
BookStoreA.set('name', 'Books of Love');
const BookStoreARelation = BookStoreA.relation("books");
BookStoreARelation.add(BookA);
await BookStoreA.save();
const BookStoreB = new Parse.Object('BookStore');
BookStoreB.set('name', 'Fantasy Books');
const BookStoreBRelation = BookStoreB.relation("books");
BookStoreBRelation.add(BookB);
await BookStoreB.save();
const BookStoreC = new Parse.Object('BookStore');
BookStoreC.set('name', 'General Books');
const BookStoreCRelation = BookStoreC.relation("books");
BookStoreCRelation.add(BookA);
BookStoreCRelation.add(BookC);
await BookStoreC.save();
console.log('Success');
Step 2 - Query the data from Android app
Now that you have populated all the classes, we can now perform some relational queries in it. Let’s begin by filtering Book
results by the publisher, searching for the ones that belong to the Publisher
“Acacia Publishings” (or “Publisher A”) using the basic ParseQuery.equalTo
method:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
progressDialog.show();
ParseQuery<ParseObject> publisherQuery = new ParseQuery<>("Publisher");
publisherQuery.whereEqualTo("name", "Acacia Publishings");
try {
ParseObject publisher = publisherQuery.getFirst();
ParseQuery<ParseObject> bookQuery = new ParseQuery<ParseObject>("Book");
bookQuery.whereEqualTo("publisher", publisher);
bookQuery.findInBackground((objects, e) -> {
progressDialog.hide();
if (e == null) {
initData(objects);
} else {
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
});
} catch (ParseException e) {
progressDialog.hide();
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
progressDialog?.show()
val publisherQuery = ParseQuery<ParseObject>("Publisher")
publisherQuery.whereEqualTo("name", "Acacia Publishings")
try {
val publisher = publisherQuery.first
val bookQuery = ParseQuery<ParseObject>("Book")
bookQuery.whereEqualTo("publisher", publisher)
bookQuery.findInBackground { objects: List<ParseObject>?, e: ParseException? ->
progressDialog?.hide()
if (e == null) {
initData(objects!!)
} else {
Toast.makeText(this, e.localizedMessage, Toast.LENGTH_SHORT).show()
}
}
} catch (e: ParseException) {
progressDialog?.hide()
e.printStackTrace()
}
Let’s now query which BookStore
objects contain Book
objects with publishing date greater than 01/01/2010, using an inner query with the ParseQuery.whereGreaterThan
method and then the ParseQuery.whereMatchesQuery
method:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
progressDialog.show();
ParseQuery<ParseObject> bookQuery = new ParseQuery<>("Book");
Calendar calendar = Calendar.getInstance();
calendar.set(2010,1,1,59,59,59);
Date date = calendar.getTime();
bookQuery.whereGreaterThan("publishingDate", date);
ParseQuery<ParseObject> bookStoreQuery = new ParseQuery<>("BookStore");
bookStoreQuery.whereMatchesQuery("books",bookQuery);
bookStoreQuery.findInBackground((objects, e) -> {
progressDialog.hide();
if (e==null){
initData(objects);
} else {
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
progressDialog?.show()
val bookQuery = ParseQuery<ParseObject>("Book")
val calendar = Calendar.getInstance()
calendar[2010, 1, 1, 59, 59] = 59
val date = calendar.time
bookQuery.whereGreaterThan("publishingDate", date)
val bookStoreQuery = ParseQuery<ParseObject>("BookStore")
bookStoreQuery.whereMatchesQuery("books", bookQuery)
bookStoreQuery.findInBackground { objects: List<ParseObject>?, e: ParseException? ->
progressDialog?.hide()
if (e == null) {
initData(objects!!)
} else {
Toast.makeText(this, e.localizedMessage, Toast.LENGTH_SHORT).show()
}
}
Now lets create a more complex relational query, looking for BookStore
objects that have at least one Book
written by Author
“Aaron Writer” (or “AuthorA”), using whereEqualTo
and whereMatchesQuery
:
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
progressDialog.show();
ParseQuery<ParseObject> authorQuery = new ParseQuery<>("Author");
authorQuery.whereEqualTo("name","Aaron Writer");
try {
ParseObject authorA = authorQuery.getFirst();
ParseQuery<ParseObject> bookQuery = new ParseQuery<>("Book");
bookQuery.whereEqualTo("authors",authorA);
ParseQuery<ParseObject> bookStoreQuery = new ParseQuery<>("BookStore");
bookStoreQuery.whereMatchesQuery("books",bookQuery);
bookStoreQuery.findInBackground((objects, e) -> {
progressDialog.hide();
if (e==null){
initData(objects);
} else {
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
});
} catch (ParseException e) {
progressDialog.hide();
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
progressDialog?.show()
val authorQuery = ParseQuery<ParseObject>("Author")
authorQuery.whereEqualTo("name", "Aaron Writer")
try {
val authorA = authorQuery.first
val bookQuery = ParseQuery<ParseObject>("Book")
bookQuery.whereEqualTo("authors", authorA)
val bookStoreQuery = ParseQuery<ParseObject>("BookStore")
bookStoreQuery.whereMatchesQuery("books", bookQuery)
bookStoreQuery.findInBackground { objects: List<ParseObject>?, e: ParseException? ->
progressDialog?.hide()
if (e == null) {
initData(objects!!)
} else {
Toast.makeText(this, e.localizedMessage, Toast.LENGTH_SHORT).show()
}
}
} catch (e: ParseException) {
progressDialog?.hide()
e.printStackTrace()
}
It’s done!
At the end of this guide, you learned how relational queries work on Parse and how to perform them on Back4App from an Android App.