---
title: Relational Queries
slug: docs/react/data-objects/relational-query
description: In this guide, you will learn how to perform relational data querying in Parse on a React application
image: https://www.back4app.com/images/logo-social.png
docTags: 
createdAt: 2024-03-19T16:06:41.125Z
---

# Relational Query in React using Parse

## Introduction

In this guide, you will perform relational queries in Parse and implement a React component using these queries. You will learn how to set up and query realistic data using Back4App and React.

## Prerequisites

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

- A React App created and [connected to Back4App](https://www.back4app.com/docs/react/quickstart).
-  If you want to run this guide’s example project, you should set up the [ library](https://ant.design/).
:::

## Goal

Query relational data stored on Back4App from a React App.

## 1 - Understanding the Parse.Query class

Any Parse query operation uses the <font color="#2166ae">`Parse.Query`</font> object type, which will help you retrieve specific data from your database throughout your app. It is crucial to know that a <font color="#2166ae">`Parse.Query` </font>will only resolve after calling a retrieve method (like <font color="#2166ae">`Parse.Query.find`</font> or <font color="#2166ae">`Parse.Query.first`</font>), so a query can be set up and several modifiers can be chained before actually being called.

To create a new <font color="#2166ae">`Parse.Query`</font>, you need to pass as a parameter the desired <font color="#2166ae">`Parse.Object`</font> subclass, which is the one that will contain your query results. An example query can be seen below, in which a fictional <font color="#2166ae">`Book` </font>subclass is being queried.

```javascript
1	// This will create your query
2	let parseQuery = new Parse.Query("Book");
3	// The query will resolve only after calling this method
4	let queryResult = await parseQuery.find();
```

You can read more about the <font color="#2166ae">`Parse.Query`</font> class [here at the official documentation](https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Query.html).

## 2 - Save some data on Back4App

Let’s create an assortment of classes, which will be the target of our queries in this guide. The classes are: <font color="#2166ae">`Author`</font>, <font color="#2166ae">`Book`</font>, <font color="#2166ae">`Publisher`</font> and <font color="#2166ae">`BookStore`</font>, in which <font color="#2166ae">`Book` </font>has a 1\:N relation with <font color="#2166ae">`Publisher` </font>and N\:N with <font color="#2166ae">`Author`</font>, and <font color="#2166ae">`BookStore` </font>has an N\:N relation with <font color="#2166ae">`Book`</font>.

On Parse JS Console it 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:

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/MrG1tC6gVb0yyGeaOpFdm_image.png)

Go ahead and create the classes with the following example content:

```javascript
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	// Publishers
16	const PublisherA = new Parse.Object('Publisher');
17	PublisherA.set('name', 'Acacia Publishings');
18	await PublisherA.save();
19	
20	const PublisherB = new Parse.Object('Publisher');
21	PublisherB.set('name', 'Birch Distributions');
22	await PublisherB.save();
23	
24	// Books
25	const BookA = new Parse.Object('Book');
26	BookA.set('title', 'A Love Story');
27	BookA.set('publisher', PublisherA);
28	BookA.set('publishingDate', new Date('05/07/1998'));
29	const BookARelation = BookA.relation("authors");
30	BookARelation.add(AuthorA);
31	await BookA.save();
32	
33	const BookB = new Parse.Object('Book');
34	BookB.set('title', 'Benevolent Elves');
35	BookB.set('publisher', PublisherB);
36	BookB.set('publishingDate', new Date('11/31/2008'));
37	const BookBRelation = BookB.relation("authors");
38	BookBRelation.add(AuthorB);
39	await BookB.save();
40	
41	const BookC = new Parse.Object('Book');
42	BookC.set('title', 'Can You Believe It?');
43	BookC.set('publisher', PublisherB);
44	BookC.set('publishingDate', new Date('08/21/2018'));
45	const BookCRelation = BookC.relation("authors");
46	BookCRelation.add(AuthorA);
47	BookCRelation.add(AuthorC);
48	await BookC.save();
49	
50	// BookStore
51	const BookStoreA = new Parse.Object('BookStore');
52	BookStoreA.set('name', 'Books of Love');
53	const BookStoreARelation = BookStoreA.relation("books");
54	BookStoreARelation.add(BookA);
55	await BookStoreA.save();
56	
57	const BookStoreB = new Parse.Object('BookStore');
58	BookStoreB.set('name', 'Fantasy Books');
59	const BookStoreBRelation = BookStoreB.relation("books");
60	BookStoreBRelation.add(BookB);
61	await BookStoreB.save();
62	
63	const BookStoreC = new Parse.Object('BookStore');
64	BookStoreC.set('name', 'General Books');
65	const BookStoreCRelation = BookStoreC.relation("books");
66	BookStoreCRelation.add(BookA);
67	BookStoreCRelation.add(BookC);
68	await BookStoreC.save();
69	
70	console.log('Success');
```

## 3 - Query the data

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 <font color="#2166ae">`publisher`</font>, searching for the ones that belong to the Publisher “Acacia Publishings” (or “Publisher A”) using the basic <font color="#2166ae">`Parse.Query.equalTo`</font> method:

```javascript
1	// Get PublisherA object
2	const PublisherAQuery = new Parse.Query('Publisher');
3	PublisherAQuery.equalTo('name', 'Acacia Publishings');
4	const PublisherA = await PublisherAQuery.first();
5	
6	// Query Books with PublisherA
7	const bookQuery = new Parse.Query('Book');
8	bookQuery.equalTo('publisher', PublisherA);
9	let queryResults = await bookQuery.find();
10	
11	// Let's show the results
12	for (let result of queryResults) {
13	  // You access `Parse.Objects` attributes by using `.get`
14	  console.log(result.get('title'));
15	};
```

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

```javascript
1	// Create inner Book query
2	const bookQuery = new Parse.Query('Book');
3	bookQuery.greaterThan('publishingDate', new Date('01/01/2010'));
4	
5	// Query BookStore using inner Book query
6	const bookStoreQuery = new Parse.Query('BookStore');
7	bookStoreQuery.matchesQuery('books', bookQuery);
8	let queryResults = await bookStoreQuery.find();
9	
10	// Let's show the results
11	for (let result of queryResults) {
12	  // You access `Parse.Objects` attributes by using `.get`
13	  console.log(result.get('name'));
14	};
```

Let’s now create a more complex relational query, looking for <font color="#2166ae">`BookStore` </font>objects that have at least one <font color="#2166ae">`Book`</font> written by <font color="#2166ae">`Author` </font>“Aaron Writer” (or “AuthorA”), using <font color="#2166ae">`equalTo` </font>and <font color="#2166ae">`matchesQuery`</font>:

```javascript
1	// Get AuthorA object
2	const AuthorAQuery = new Parse.Query('Author');
3	AuthorAQuery.equalTo('name', 'Aaron Writer');
4	const AuthorA = await AuthorAQuery.first();
5	
6	// Create inner Book query
7	const bookQuery = new Parse.Query('Book');
8	bookQuery.equalTo('authors', AuthorA);
9	
10	// Query BookStore using inner Book query
11	const bookStoreQuery = new Parse.Query('BookStore');
12	bookStoreQuery.matchesQuery('books', bookQuery);
13	let queryResults = await bookStoreQuery.find();
14	
15	// Let's show the results
16	for (let result of queryResults) {
17	  // You access `Parse.Objects` attributes by using `.get`
18	  console.log(result.get('name'));
19	};
```

## 4 - Query from a React component

Let’s now use our example queries inside a component in React, with a simple interface having a list showing results and also buttons for calling the queries. This is how the component code is laid out, note the <font color="#2166ae">`doQuery` </font>functions, containing the example code from before.

:::CodeblockTabs
JavaScript

```javascript
1	import React, { useState } from 'react';
2	import Parse from 'parse/dist/parse.min.js';
3	import './App.css';
4	import { Button, Divider } from 'antd';
5	import { CloseOutlined, SearchOutlined } from '@ant-design/icons';
6	
7	export const QueryRelational = () => {
8	  // State variable
9	  const [queryResults, setQueryResults] = useState();
10	
11	  const doQueryA = async function () {
12	    // Get PublisherA object
13	    const PublisherAQuery = new Parse.Query('Publisher');
14	    PublisherAQuery.equalTo('name', 'Acacia Publishings');
15	    const PublisherA = await PublisherAQuery.first();
16	
17	    // Query Books with PublisherA
18	    const bookQuery = new Parse.Query('Book');
19	    bookQuery.equalTo('publisher', PublisherA);
20	
21	    try {
22	      let results = await bookQuery.find();
23	      setQueryResults(results);
24	      return true;
25	    } catch (error) {
26	      // Error can be caused by lack of Internet connection
27	      alert(`Error! ${error.message}`);
28	      return false;
29	    }
30	  };
31	
32	  const doQueryB = async function () {
33	    // Create inner Book query
34	    const bookQuery = new Parse.Query('Book');
35	    bookQuery.greaterThan('publishingDate', new Date('01/01/2010'));
36	
37	    // Query BookStore using inner Book query
38	    const bookStoreQuery = new Parse.Query('BookStore');
39	    bookStoreQuery.matchesQuery('books', bookQuery);
40	
41	    try {
42	      let results = await bookStoreQuery.find();
43	      setQueryResults(results);
44	      return true;
45	    } catch (error) {
46	      // Error can be caused by lack of Internet connection
47	      alert(`Error! ${error.message}`);
48	      return false;
49	    }
50	  };
51	
52	  const doQueryC = async function () {
53	    // Get AuthorA object
54	    const AuthorAQuery = new Parse.Query('Author');
55	    AuthorAQuery.equalTo('name', 'Aaron Writer');
56	    const AuthorA = await AuthorAQuery.first();
57	
58	    // Create inner Book query
59	    const bookQuery = new Parse.Query('Book');
60	    bookQuery.equalTo('authors', AuthorA);
61	
62	    // Query BookStore using inner Book query
63	    const bookStoreQuery = new Parse.Query('BookStore');
64	    bookStoreQuery.matchesQuery('books', bookQuery);
65	
66	    try {
67	      let results = await bookStoreQuery.find();
68	      setQueryResults(results);
69	      return true;
70	    } catch (error) {
71	      // Error can be caused by lack of Internet connection
72	      alert(`Error! ${error.message}`);
73	      return false;
74	    }
75	  };
76	
77	  const clearQueryResults = async function () {
78	    setQueryResults(undefined);
79	    return true;
80	  };
81	
82	  return (
83	    <div>
84	      <div className="header">
85	        <img
86	          className="header_logo"
87	          alt="Back4App Logo"
88	          src={
89	            'https://blog.back4app.com/wp-content/uploads/2019/05/back4app-white-logo-500px.png'
90	          }
91	        />
92	        <p className="header_text_bold">{'React on Back4App'}</p>
93	        <p className="header_text">{'Relational Queries'}</p>
94	      </div>
95	      <div className="container">
96	        <div className="flex_between">
97	          <h2 className="heading">{'Query List'}</h2>
98	          <div className="flex">
99	            <Button
100	              onClick={() => doQueryA()}
101	              type="primary"
102	              className="heading_button"
103	              color={'#208AEC'}
104	              icon={<SearchOutlined />}
105	            >
106	              QUERY A
107	            </Button>
108	            <Button
109	              onClick={() => doQueryB()}
110	              type="primary"
111	              className="heading_button"
112	              color={'#208AEC'}
113	              icon={<SearchOutlined />}
114	            >
115	              QUERY B
116	            </Button>
117	            <Button
118	              onClick={() => doQueryC()}
119	              type="primary"
120	              className="heading_button"
121	              color={'#208AEC'}
122	              icon={<SearchOutlined />}
123	            >
124	              QUERY C
125	            </Button>
126	            <Button
127	              onClick={() => clearQueryResults()}
128	              type="primary"
129	              className="heading_button"
130	              color={'#208AEC'}
131	              icon={<CloseOutlined />}
132	            >
133	              CLEAR RESULTS
134	            </Button>
135	          </div>
136	        </div>
137	        <Divider />
138	        <div className="flex_between">
139	          <div className="flex_child">
140	            {/* Query list */}
141	            {queryResults !== undefined &&
142	              queryResults.map((result, index) => (
143	                <div className="list_item" key={`${index}`}>
144	                  <p className="list_item_title">{`${
145	                    result.get('name') !== undefined
146	                      ? result.get('name')
147	                      : result.get('title')
148	                  }`}</p>
149	                </div>
150	              ))}
151	            {queryResults !== undefined && queryResults.length <= 0 ? (
152	              <p>{'No results here!'}</p>
153	            ) : null}
154	          </div>
155	        </div>
156	      </div>
157	    </div>
158	  );
159	};
```

TypeScript

```typescript
1	import React, { useState, FC, ReactElement } from 'react';
2	import './App.css';
3	import { Button, Divider } from 'antd';
4	import { CloseOutlined, SearchOutlined } from '@ant-design/icons';
5	const Parse = require('parse/dist/parse.min.js');
6	
7	export const QueryRelational: FC<{}> = (): ReactElement => {
8	  // State variable
9	  const [queryResults, setQueryResults] = useState<Parse.Object[]>();
10	
11	  const doQueryA = async function (): Promise<boolean> {
12	    // Get PublisherA object
13	    const PublisherAQuery: Parse.Query = new Parse.Query('Publisher');
14	    PublisherAQuery.equalTo('name', 'Acacia Publishings');
15	    const PublisherA: Parse.Object | undefined = await PublisherAQuery.first();
16	
17	    // Query Books with PublisherA
18	    const bookQuery: Parse.Query = new Parse.Query('Book');
19	    bookQuery.equalTo('publisher', PublisherA);
20	
21	    try {
22	      let results: Parse.Object[] = await bookQuery.find();
23	      setQueryResults(results);
24	      return true;
25	    } catch (error) {
26	      // Error can be caused by lack of Internet connection
27	      alert(`Error! ${error.message}`);
28	      return false;
29	    }
30	  };
31	
32	  const doQueryB = async function (): Promise<boolean> {
33	    // Create inner Book query
34	    const bookQuery: Parse.Query = new Parse.Query('Book');
35	    bookQuery.greaterThan('publishingDate', new Date('01/01/2010'));
36	
37	    // Query BookStore using inner Book query
38	    const bookStoreQuery: Parse.Query = new Parse.Query('BookStore');
39	    bookStoreQuery.matchesQuery('books', bookQuery);
40	
41	    try {
42	      let results: Parse.Object[] = await bookStoreQuery.find();
43	      setQueryResults(results);
44	      return true;
45	    } catch (error) {
46	      // Error can be caused by lack of Internet connection
47	      alert(`Error! ${error.message}`);
48	      return false;
49	    }
50	  };
51	
52	  const doQueryC = async function (): Promise<boolean> {
53	    // Get AuthorA object
54	    const AuthorAQuery: Parse.Query = new Parse.Query('Author');
55	    AuthorAQuery.equalTo('name', 'Aaron Writer');
56	    const AuthorA: Parse.Object | undefined = await AuthorAQuery.first();
57	
58	    // Create inner Book query
59	    const bookQuery: Parse.Query = new Parse.Query('Book');
60	    bookQuery.equalTo('authors', AuthorA);
61	
62	    // Query BookStore using inner Book query
63	    const bookStoreQuery: Parse.Query = new Parse.Query('BookStore');
64	    bookStoreQuery.matchesQuery('books', bookQuery);
65	
66	    try {
67	      let results: Parse.Object[] = await bookStoreQuery.find();
68	      setQueryResults(results);
69	      return true;
70	    } catch (error) {
71	      // Error can be caused by lack of Internet connection
72	      alert(`Error! ${error.message}`);
73	      return false;
74	    }
75	  };
76	
77	  const clearQueryResults = async function (): Promise<boolean> {
78	    setQueryResults(undefined);
79	    return true;
80	  };
81	
82	  return (
83	    <div>
84	      <div className="header">
85	        <img
86	          className="header_logo"
87	          alt="Back4App Logo"
88	          src={
89	            'https://blog.back4app.com/wp-content/uploads/2019/05/back4app-white-logo-500px.png'
90	          }
91	        />
92	        <p className="header_text_bold">{'React on Back4App'}</p>
93	        <p className="header_text">{'Relational Queries'}</p>
94	      </div>
95	      <div className="container">
96	        <div className="flex_between">
97	          <h2 className="heading">{'Query List'}</h2>
98	          <div className="flex">
99	            <Button
100	              onClick={() => doQueryA()}
101	              type="primary"
102	              className="heading_button"
103	              color={'#208AEC'}
104	              icon={<SearchOutlined />}
105	            >
106	              QUERY A
107	            </Button>
108	            <Button
109	              onClick={() => doQueryB()}
110	              type="primary"
111	              className="heading_button"
112	              color={'#208AEC'}
113	              icon={<SearchOutlined />}
114	            >
115	              QUERY B
116	            </Button>
117	            <Button
118	              onClick={() => doQueryC()}
119	              type="primary"
120	              className="heading_button"
121	              color={'#208AEC'}
122	              icon={<SearchOutlined />}
123	            >
124	              QUERY C
125	            </Button>
126	            <Button
127	              onClick={() => clearQueryResults()}
128	              type="primary"
129	              className="heading_button"
130	              color={'#208AEC'}
131	              icon={<CloseOutlined />}
132	            >
133	              CLEAR RESULTS
134	            </Button>
135	          </div>
136	        </div>
137	        <Divider />
138	        <div className="flex_between">
139	          <div className="flex_child">
140	            {/* Query list */}
141	            {queryResults !== undefined &&
142	              queryResults.map((result: Parse.Object, index: number) => (
143	                <div className="list_item" key={`${index}`}>
144	                  <p className="list_item_title">{`${result.get('name') !== undefined ? result.get('name') : result.get('title')}`}</p>
145	                </div>
146	              ))}
147	            {queryResults !== undefined &&
148	            queryResults.length <= 0 ? (
149	              <p>{'No results here!'}</p>
150	            ) : null}
151	          </div>
152	        </div>
153	      </div>
154	    </div>
155	  );
156	};
```
:::

Also add these classes to your <font color="#2166ae">`App.css`</font> file to fully render the component layout:

:::CodeblockTabs
App.css

```css
1	@import '~antd/dist/antd.css';
2	
3	.App {
4	  text-align: center;
5	}
6	
7	html {
8	  box-sizing: border-box;
9	  outline: none;
10	  overflow: auto;
11	}
12	
13	*,
14	*:before,
15	*:after {
16	  margin: 0;
17	  padding: 0;
18	  box-sizing: inherit;
19	}
20	
21	h1,
22	h2,
23	h3,
24	h4,
25	h5,
26	h6 {
27	  margin: 0;
28	  font-weight: bold;
29	}
30	
31	p {
32	  margin: 0;
33	}
34	
35	body {
36	  margin: 0;
37	  background-color: #fff;
38	}
39	
40	.container {
41	  width: 100%;
42	  max-width: 900px;
43	  margin: auto;
44	  padding: 20px 0;
45	  text-align: left;
46	}
47	
48	.header {
49	  align-items: center;
50	  padding: 25px 0;
51	  background-color: #208AEC;
52	}
53	
54	.header_logo {
55	  height: 55px;
56	  margin-bottom: 20px;
57	  object-fit: contain;
58	}
59	
60	.header_text_bold {
61	  margin-bottom: 3px;
62	  color: rgba(255, 255, 255, 0.9);
63	  font-size: 16px;
64	  font-weight: bold;
65	}
66	
67	.header_text {
68	  color: rgba(255, 255, 255, 0.9);
69	  font-size: 15px;
70	}
71	
72	.heading {
73	  font-size: 22px;
74	}
75	
76	.flex {
77	  display: flex;
78	}
79	
80	.flex_between {
81	  display: flex;
82	  justify-content: space-between;
83	}
84	
85	.flex_child {
86	  flex: 0 0 45%;
87	}
88	
89	.heading_button {
90	  margin-left: 12px;
91	}
92	
93	.list_item {
94	  padding-bottom: 15px;
95	  margin-bottom: 15px;
96	  border-bottom: 1px solid rgba(0,0,0,0.06);
97	  text-align: left;
98	}
99	
100	.list_item_title {
101	  color: rgba(0,0,0,0.87);
102	  font-size: 17px;
103	}
```
:::

This is how the component should look like after rendering and querying by one of the query functions:

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/y52ncClgNZmWznwkc1c4C_image.png)

## Conclusion

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