Android

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:

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:

React Native Back4App

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.