---
title: Relational Queries
slug: back4app/YmFZheNC8VeurRhGD1oF5
description: In this guide, you'll learn how to perform relational data querying in Parse on a Flutter application
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-18T12:08:53.051Z
---

# Parse Relational Query in Flutter

## Introduction

You’ve already seen [how to store relational data objects](https://www.back4app.com/docs/flutter/parse-sdk/data-objects/flutter-one-to-many-relationship) using the<font color="#2166ae">`Parse.Pointer`</font> and <font color="#2166ae">`Parse.Relations`</font> data types. You’ve learned that on Parse it is possible to use any <font color="#2166ae">`ParseObject`</font> as a value in other <font color="#2166ae">`ParseObject`</font>, establishing a relation between them. Internally, the Parse framework will store the referred-to object in just one place to maintain consistency. That can give you extra power when building and running complex queries.

Also, you’ve already [learned how to use a QueryBuilder](https://www.back4app.com/docs/flutter/parse-sdk/data-objects/flutter-query) with <font color="#2166ae">`get`</font> can retrieve a single <font color="#2166ae">`ParseObject`</font> from Back4App. There are many other ways to retrieve data with <font color="#2166ae">`QueryBuilder`</font>.

In this guide, you will ding deep into the <font color="#2166ae">`QueryBuilder`</font> class and see methods you can use to build Relational Queries. You will use a simple database class with some mocked data to perform the Queries using Flutter on Back4App.

## Prerequisites

:::hint{type="info"}
**To complete this tutorial, you will need:**

- [Android Studio ](https://developer.android.com/studio)or [VS Code installed](https://code.visualstudio.com/) (with [Plugins](https://docs.flutter.dev/get-started/editor) Dart and Flutter)
- An app [created](https://www.back4app.com/docs/get-started/new-parse-app) on Back4App:
  - **Note:&#x20;**&#x46;ollow the [New Parse App Tutorial](https://www.back4app.com/docs/get-started/new-parse-app) to learn how to create a Parse App on Back4App.
- An Flutter app connected to Back4app.
  - **Note:&#x20;**&#x46;ollow the [Install Parse SDK on Flutter project](https://www.back4app.com/docs/flutter/parse-sdk/parse-flutter-sdk) to create an Flutter Project connected to Back4App.
- A device (or virtual device) running Android or iOS.
:::

## Goal

Query relational data stored on Back4App from a Flutter App.

## 1 - Understanding the QueryBuilder class

Any Parse query operation uses the <font color="#2166ae">`QueryBuilder`</font> object type, which will help you retrieve specific data from your database throughout your app.

To create a new <font color="#2166ae">`QueryBuilder`</font>, you need to pass as a parameter the desired <font color="#2166ae">`ParseObject`</font> subclass, which is the one that will contain your query results.

It is crucial to know that a <font color="#2166ae">`QueryBuilder`</font> will only resolve after calling a retrieve method <font color="#2166ae">`query`</font>, so a query can be set up and several modifiers can be chained before actually being called.

```dart
1	       // This will create your query
2      QueryBuilder<ParseObject> queryBook =
3           QueryBuilder<ParseObject>(ParseObject('Book'));
4        
5       	// The query will resolve only after calling this method
6      final ParseResponse apiResponse = await queryBook.query();
7	
8       if (apiResponse.success && apiResponse.results != null) {
9         ....
10      } else {
11  	   ...
12      }
```

You can read more about the QueryBuilder class [here at the official documentation](https://github.com/parse-community/Parse-SDK-Flutter/tree/master/packages/flutter#complex-queries).

## Using the JavaScript Console on Back4App

Inside your Back4App application’s dashboard, you will find a very useful API console in which you can run JavaScript code directly. In this guide you will use to store data objects in Back4App. On your App main dashboard go to <font color="#2166ae">`Core->API Console->Javascript`</font>.

![](https://api.main.archbee.co/api/optimize/yD3zCY-NNBBIfd0uqcfR5/uAoF6bUPQ86DeL5ddVeH-_image.png)

## 2 - Save Data on Back4app

To run the queries on this guide you’ll need first to populate your App with some data.

The classes are: <font color="#2166ae">`Author`</font>, <font color="#2166ae">`Book`</font>, <font color="#2166ae">`Publisher`</font> and <font color="#2166ae">`BookStore`</font>.
Which <font color="#2166ae">`Book`</font> has a <font color="#2166ae">`1:N`</font> relation with <font color="#2166ae">`Publisher`</font> and <font color="#2166ae">`N:N`</font> with <font color="#2166ae">`Author`</font>, and <font color="#2166ae">`BookStore`</font> has an <font color="#2166ae">`N:N`</font> relation with <font color="#2166ae">`Book`</font>.

Here is the <font color="#2166ae">`Parse.Object`</font> classes creation code, so go ahead and run it in your API console:

```dart
1   // Add objects and create tables
2   // Authors
3   const AuthorA = new Parse.Object('Author');
4   AuthorA.set('name', 'Aaron Writer');
5   await AuthorA.save();
6
7   const AuthorB = new Parse.Object('Author');
8   AuthorB.set('name', 'Beatrice Novelist');
9   await AuthorB.save();
10
11  const AuthorC = new Parse.Object('Author');
12  AuthorC.set('name', 'Casey Columnist');
13  await AuthorC.save();
14
15  const AuthorD = new Parse.Object('Author');
16  AuthorD.set('name', 'Gary Stur');
17  await AuthorD.save();
18
19  const AuthorE = new Parse.Object('Author');
20  AuthorE.set('name', 'Mary Sue');
21  await AuthorE.save();
22
23  // Publishers
24  const PublisherA = new Parse.Object('Publisher');
25  PublisherA.set('name', 'Acacia Publishings');
26  await PublisherA.save();
27
28  const PublisherB = new Parse.Object('Publisher');
29  PublisherB.set('name', 'Birch Distributions');
30  await PublisherB.save();
31  
32  const PublisherC = new Parse.Object('Publisher');
33  PublisherC.set('name', 'Acacia Distributions');
34  await PublisherC.save();
35
36
37  // Books
38  const BookA = new Parse.Object('Book');
39  BookA.set('title', 'A Love Story');
40  BookA.set('publisher', PublisherA);
41  BookA.set('publishingDate', new Date('05/07/1998'));
42  const BookARelation = BookA.relation("authors");
43  BookARelation.add(AuthorA);
44  await BookA.save();
45 
46  const BookB = new Parse.Object('Book');
47  BookB.set('title', 'Benevolent Elves');
48  BookB.set('publisher', PublisherB);
49  BookB.set('publishingDate', new Date('11/31/2008'));
50  const BookBRelation = BookB.relation("authors");
51  BookBRelation.add(AuthorB);
52  await BookB.save();
53 
54  const BookC = new Parse.Object('Book');
55  BookC.set('title', 'Can You Believe It?');
56  BookC.set('publisher', PublisherB);
57  BookC.set('publishingDate', new Date('08/21/2018'));
58  const BookCRelation = BookC.relation("authors");
59  BookCRelation.add(AuthorA);
60  BookCRelation.add(AuthorC);
61  await BookC.save();
62
63  // BookStore
64  const BookStoreA = new Parse.Object('BookStore');
65  BookStoreA.set('name', 'Books of Love');
66  const BookStoreARelation = BookStoreA.relation("books");
67  BookStoreARelation.add(BookA);
68  await BookStoreA.save();
69  
70  const BookStoreB = new Parse.Object('BookStore');
71  BookStoreB.set('name', 'Fantasy Books');
72  const BookStoreBRelation = BookStoreB.relation("books");
73  BookStoreBRelation.add(BookB);
74  await BookStoreB.save();
75  
76  const BookStoreC = new Parse.Object('BookStore');
77  BookStoreC.set('name', 'General Books');
78  const BookStoreCRelation = BookStoreC.relation("books");
79  BookStoreCRelation.add(BookA);
80  BookStoreCRelation.add(BookC);
81  await BookStoreC.save();
82 
83  console.log('Success');
```

After running this code, you should now have a <font color="#2166ae">`Author`</font>, <font color="#2166ae">`Publisher`</font>, <font color="#2166ae">`Book`</font> and <font color="#2166ae">`BookStore`</font> class in your database.

Your new class should look like this:

![](https://api.main.archbee.co/api/optimize/yD3zCY-NNBBIfd0uqcfR5/8xnDcV6IaJ9WNPPw9ZiSY_image.png)

Let’s now take a look at examples from every <font color="#2166ae">`QueryBuilder`</font> method, along with brief explanations on what they do.

## 3 - Query the data

Now that you have a populated class, we can now perform some relational queries

Now that you have populated all the classes, we can now perform some relational queries in it.

Let’s begin by filtering <font color="#2166ae">`Book`</font> results by the publisher, searching for the ones that belong to the <font color="#2166ae">`Publisher`</font> *“Acacia Publishings”* (or “Publisher A”) with relational Pointer using the basic <font color="#2166ae">`.whereEqualTo`</font> method:

```dart
1       // Get PublisherA object
2       final QueryBuilder<ParseObject> publisherQueryA =
3           QueryBuilder<ParseObject>(ParseObject('Publisher'))
4             ..whereEqualTo('name', 'Acacia Publishings');
5   
6       final ParseResponse publisherResponse = await publisherQueryA.query();
7       if (!publisherResponse.success) {
8         return;
9       }
10      final publisherA = publisherResponse.results?.first as ParseObject;
11
12      // Query Books with PublisherA
13      final QueryBuilder<ParseObject> bookQuery =
14          QueryBuilder<ParseObject>(ParseObject('Book'))
15            ..whereEqualTo('publisher', publisherA);
16
17      final ParseResponse bookResponse = await bookQuery.query();
18      if (!bookResponse.success) {
19        return;
20      }
21  
22      for (var book in bookResponse.results as List<ParseObject>) {
23        print(book.get('title'));
24      }
```

Let’s now query which <font color="#2166ae">`BookStore`</font> objects contain <font color="#2166ae">`Book`</font> objects with publishing date greater than <font color="#2166ae">`01/01/2010`</font>, using an inner query with the <font color="#2166ae">`whereGreaterThan`</font> method and then the <font color="#2166ae">`whereMatchesQuery`</font> method:

```dart
1   // Create inner Book query
2       final QueryBuilder<ParseObject> bookQuery =
3           QueryBuilder<ParseObject>(ParseObject('Book'))
4             ..whereGreaterThan('publishingDate', DateTime(2010, 01, 01));
5
6       // Query BookStore using inner Book query
7       final QueryBuilder<ParseObject> bookStoreQuery =
8           QueryBuilder<ParseObject>(ParseObject('BookStore'))
9             ..whereMatchesQuery('books', bookQuery);
10  
11      final ParseResponse bookStoreResponse = await bookStoreQuery.query();
12      if (!bookStoreResponse.success) {
13        return;
14      }
15
16      for (var b in bookStoreResponse.results as List<ParseObject>) {
17        print(b.get('name'));
18      }
```

Let’s now create another query, looking for Authors that are relation with the book **Can You Believe It**?, using <font color="#2166ae">`whereRelatedTo`</font>:

```dart
1       // Get Book object
2       final QueryBuilder<ParseObject> bookQuery =
3           QueryBuilder<ParseObject>(ParseObject('Book'))
4             ..whereEqualTo('title', 'Can You Believe It?');
5
6       final ParseResponse bookResponse = await bookQuery.query();
7       if (!bookResponse.success) {
8         return;
9       }
10
11      final book = bookResponse.results?.first as ParseObject;
12
13      // Get Author with relation with Book Can You Believe It?
14      final QueryBuilder<ParseObject> authorsQuery =
15          QueryBuilder<ParseObject>(ParseObject('Author'))
16            ..whereRelatedTo('authors', 'Book', book.objectId!);
17
18      final ParseResponse authorResponse = await authorsQuery.query();
19
20      // Let's show the results
21      if (authorResponse.success && authorResponse.results != null) {
22        for (var a in authorResponse.results! as List<ParseObject>) {
23          print(a.get('name'));
24        }
25      }
```

## 4 - Query from Flutter

Let’s now use our example queries inside a Flutter App, with a simple interface having a list showing results and also 3 buttons for calling the queries.

Open your Flutter project, go to the main.dart file, clean up all the code, and replace it with:

```dart
1   import 'package:flutter/cupertino.dart';
2   import 'package:flutter/material.dart';
3   import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
4
5   void main() async {
6     WidgetsFlutterBinding.ensureInitialized();
7
8     final keyApplicationId = 'YOUR_APP_ID_HERE';
9     final keyClientKey = 'YOUR_CLIENT_KEY_HERE';
10    final keyParseServerUrl = 'https://parseapi.back4app.com';
11
12    await Parse().initialize(keyApplicationId, keyParseServerUrl,
13        clientKey: keyClientKey, debug: true);
14
15    runApp(MaterialApp(
16      title: 'Flutter - GeoPoint',
17      debugShowCheckedModeBanner: false,
18      home: HomePage(),
19    ));
20  }
21
22  class HomePage extends StatefulWidget {
23    @override
24    _HomePageState createState() => _HomePageState();
25  }
26 
27  class _HomePageState extends State<HomePage> {
28    List<ParseObject> results = <ParseObject>[];
29    double selectedDistance = 3000;
30  
31    void doQueryPointer() async {
32      // Get PublisherA object
33      final QueryBuilder<ParseObject> publisherQueryA =
34          QueryBuilder<ParseObject>(ParseObject('Publisher'))
35            ..whereEqualTo('name', 'Acacia Publishings');
36
37      final ParseResponse publisherResponse = await publisherQueryA.query();
38      if (!publisherResponse.success) {
39        return;
40      }
41      final publisherA = publisherResponse.results?.first as ParseObject;
42  
43      // Query Books with PublisherA
44      final QueryBuilder<ParseObject> bookQuery =
45          QueryBuilder<ParseObject>(ParseObject('Book'))
46            ..whereEqualTo('publisher', publisherA);
47  
48      final ParseResponse bookResponse = await bookQuery.query();
49  
50      if (!bookResponse.success) {
51        setState(() {
52          results.clear();
53        });
54      } else {
55        setState(() {
56          results = bookResponse.results as List<ParseObject>;
57        });
58      }
59    }
60
61    void doQueryMatches() async {
62      // Create inner Book query
63      final QueryBuilder<ParseObject> bookQuery =
64          QueryBuilder<ParseObject>(ParseObject('Book'))
65            ..whereGreaterThan('publishingDate', DateTime(2010, 01, 01));
66
67      // Query BookStore using inner Book query
68      final QueryBuilder<ParseObject> bookStoreQuery =
69          QueryBuilder<ParseObject>(ParseObject('BookStore'))
70            ..whereMatchesQuery('books', bookQuery);
71  
72      final ParseResponse bookStoreResponse = await bookStoreQuery.query();
73      if (!bookStoreResponse.success) {
74        setState(() {
75          results.clear();
76        });
77      } else {
78        setState(() {
79          results = bookStoreResponse.results as List<ParseObject>;
80        });
81      }
82    }
83  
84    void doQueryRelatedTo() async {
85      // Get Book object
86      final QueryBuilder<ParseObject> bookQuery =
87          QueryBuilder<ParseObject>(ParseObject('Book'))
88            ..whereEqualTo('title', 'Can You Believe It?');
89  
90      final ParseResponse bookResponse = await bookQuery.query();
91      if (!bookResponse.success) {
92        return;
93      }
94
95      final book = bookResponse.results?.first as ParseObject;
96  
97      // Get Author with relation with Book Can You Believe It?
98      final QueryBuilder<ParseObject> authorsQuery =
99          QueryBuilder<ParseObject>(ParseObject('Author'))
100           ..whereRelatedTo('authors', 'Book', book.objectId!);
101 
102     final ParseResponse authorResponse = await authorsQuery.query();
103 
104     if (!authorResponse.success) {
105       setState(() {
106         results.clear();
107       });
108     } else {
109       setState(() {
110         results = authorResponse.results as List<ParseObject>;
111       });
112     }
113   }
114 
115   void doClearResults() async {
116     setState(() {
117       results.clear();
118     });
119   }
120
121   @override
122   Widget build(BuildContext context) {
123     return Scaffold(
124         body: Padding(
125       padding: const EdgeInsets.all(16.0),
126       child: Column(
127         crossAxisAlignment: CrossAxisAlignment.stretch,
128         children: [
129           Container(
130             height: 200,
131             child: Image.network(
132                 'https://blog.back4app.com/wp-content/uploads/2017/11/logo-b4a-1-768x175-1.png'),
133           ),
134           Center(
135             child: const Text('Flutter on Back4app - GeoPoint',
136                 style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
137           ),
138           SizedBox(
139             height: 8,
140           ),
141           Container(
142             height: 50,
143            child: ElevatedButton(
144                 onPressed: doQueryPointer,
145                 child: Text('Query A'),
146                 style: ElevatedButton.styleFrom(primary: Colors.blue)),
147           ),
148           SizedBox(
149             height: 8,
150           ),
151           Container(
152             height: 50,
153             child: ElevatedButton(
154                 onPressed: doQueryMatches,
155                 child: Text('Query B'),
156                 style: ElevatedButton.styleFrom(primary: Colors.blue)),
157           ),
158           SizedBox(
159             height: 8,
160           ),
161           Container(
162             height: 50,
163             child: ElevatedButton(
164                 onPressed: doQueryRelatedTo,
165                 child: Text('Query C'),
166                 style: ElevatedButton.styleFrom(primary: Colors.blue)),
167           ),
168           SizedBox(
169             height: 8,
170           ),
171           Container(
172             height: 50,
173             child: ElevatedButton(
174                 onPressed: doClearResults,
175                 child: Text('Clear results'),
176                 style: ElevatedButton.styleFrom(primary: Colors.blue)),
177           ),
178           SizedBox(
179             height: 8,
180           ),
181           Text(
182             'Result List: ${results.length}',
183           ),
184           Expanded(
185             child: ListView.builder(
186                 itemCount: results.length,
187                 itemBuilder: (context, index) {
188                   final o = results[index];
189                   return Container(
190                     padding: const EdgeInsets.all(4),
191                     decoration:
192                         BoxDecoration(border: Border.all(color: Colors.black)),
193                     child: Text('${o.toString()}'),
194                   );
195                 }),
196           )
197         ],
198       ),
199     ));
200   }
201 }
```

Find your Application Id and Client Key credentials navigating to your app Dashboard at [Back4App Website](https://www.back4app.com/).

Update your code in <font color="#2166ae">`main.dart`</font> 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.

::Image[]{src="https://api.main.archbee.co/api/optimize/yD3zCY-NNBBIfd0uqcfR5/qXtf2dBOzL7kRy1zt_5Cj_image.png" size="30" width="321" height="631" position="center" showCaption="false"}

## Conclusion

At the end of this guide, you learned how relational queries work on Parse and how to perform them on Back4App from a Flutter App. In the next guide, you will learn how to work with Users in Parse.
