Get Started

Relational Schema on Back4App

Introduction

In this guide, you will explore the relational data schema on Back4App by saving and querying related data objects.
At Back4App, different classes can share the same object. Internally, the Parse framework will store the referred object in just one place to maintain consistency. That can give you extra power when building and running complex queries.

Back4App supports relational queries by using the data types Pointers and Relations. In this guide, you will see how to query data related using Relations.

Goals

  • To store and query relational data objects on Back4App

Prerequisites

To complete this tutorial, you will need:

Let’s first create two sample classes of Parse.Object in your test app and populate it with some data, so that you can query them later.
The class State contains the text field state_name. The class City has the text field city_name and a pointer field state, redirecting to the State class.

You don’t need to specify ahead of time what keys exist on each Parse.Object, the sample classes will be created with the corresponding types in your Back4App app automatically, including the relations between both classes.

Find below code samples for most of the Parse SDKs.

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
//Initialize Parse
Parse.initialize('YOUR_APP_ID_HERE','YOUR_JAVASCRIPT_KEY_HERE');
Parse.serverURL = 'https://parseapi.back4app.com/';

async function createSampleObjects() {
  // Create State class and it's records
  const newState1 = new Parse.Object("State");
  // Define its attributes
  newState1.set("state_name", "California");
  try {
    // Save the Object
    let result = await newState1.save();
  } catch (error) {
    console.log(`Failed to create new object, with error code: ${error.message}`);
    return false;
  }
  const newState2 = new Parse.Object("State");
  newState2.set("state_name", "Colorado");
  try {
    let result = await newState2.save();
  } catch (error) {
    console.log(`Failed to create new object, with error code: ${error.message}`);
    return false;
  }

  // Create City class and it's records
  const newCity1 = new Parse.Object("City");
  // Define its attributes
  newCity1.set("city_name", "Los Angeles");
  // To create a relation, pass the Parse Object as the field value
  newCity1.set("state", newState1);
  try {
    // Save the Object
    let result = await newCity1.save();
  } catch (error) {
    console.log(`Failed to create new object, with error code: ${error.message}`);
    return false;
  }
  const newCity2 = new Parse.Object("City");
  newCity2.set("city_name", "Denver");
  newCity2.set("state", newState2);
  try {
    let result = await newCity2.save();
  } catch (error) {
    console.log(`Failed to create new object, with error code: ${error.message}`);
    return false;
  }
  console.log("Success creating classes and records!");
}

Isn’t Parse SDK for JavaScript working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to JavaScript projects or React Native Quickstart Guide.

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
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Create State class and it's records
        ParseObject newState1 = new  ParseObject("State");
        // Define its attributes
        newState1.put("state_name", "California");
        // Save the Object
        newState1.saveInBackground(e -> {
            if (e != null){
                Log.e("msg", e.getLocalizedMessage());
            }else{
                Log.d("msg","Object saved.");
            }
        });

        ParseObject newState2 = new  ParseObject("State");
        newState2.put("state_name", "Colorado");
        newState2.saveInBackground(e -> {
            if (e != null){
                Log.e("msg", e.getLocalizedMessage());
            }else{
                Log.d("msg","Object saved.");
            }
        });

        // Create City class and it's records
        ParseObject newCity1 = new  ParseObject("City");
        // Define its attributes
        newCity1.put("city_name", "Los Angeles");
        // To create a relation, pass the Parse Object as the field value
        newCity1.put("state", newState1);
        // Save the Object
        newCity1.saveInBackground(e -> {
            if (e != null){
                Log.e("msg", e.getLocalizedMessage());
            }else{
                Log.d("msg","Object saved.");
            }
        });

        ParseObject newCity2 = new  ParseObject("City");
        newCity2.put("city_name", "Denver");
        newCity2.put("state", newState2);
        newCity2.saveInBackground(e -> {
            if (e != null){
                Log.e("msg", e.getLocalizedMessage());
            }else{
                Log.d("msg","Object saved.");
            }
        });
    }
}

Isn’t Parse SDK for Android working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to Android projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for Android.

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
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, autoSendSessionId: true);

  createSampleObjects();
}

void createSampleObjects() async {
   // Create State class and it's records
  var newState1 = ParseObject('State');
  // Define its attributes
  newState1.set('state_name', 'California');
  try{
    // Save the Object
    await newState1.save();
    print('Object saved');
  } catch (e){
    print(e);
  }

  var newState2 = ParseObject("State");
  newState2.set("state_name", "Colorado");
  try{
    await newState2.save();
    print("Object saved");
  } catch (e){
    print(e);
  }

  // Create City class and it's records
  var newCity1 = ParseObject("City");
  // Define its attributes
  newCity1.set("city_name", "Los Angeles");
  // To create a relation, pass the Parse Object as the field value
  newCity1.set("state", newState1);
  try{
    // Save the Object
    await newCity1.save();
    print("Object saved");
  } catch (e){
    print(e);
  }

  var newCity2 = ParseObject("City");
  newCity2.set("city_name", "Denver");
  newCity2.set("state", newState2);
  try{
    await newCity2.save();
    print("Object saved");
  } catch (e){
    print(e);
  }
}

Isn’t Parse SDK for Flutter working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to Flutter projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for Flutter.

Isn’t Parse SDK for iOS working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to iOS Swift and iOS ObjC projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for iOS.

1

Isn’t Parse SDK for .NET working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to .NET projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for .NET.

1

Isn’t Parse SDK for Unity working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to Unity projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for Unity.

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
//Initialize Parse
ParseClient::initialize("YOUR_APP_ID_HERE", "YOUR_REST_KEY_HERE", "YOUR_MASTER_KEY_HERE");
ParseClient::setServerURL('https://parseapi.back4app.com','/');

    // Create State class and it's records
    $newState1 = new ParseObject("State");
    // Define its attributes
    $newState1->set("state_name", "California");
    try {
        // Save the Object
      $newState1->save();
      echo 'Object saved';
    } catch (ParseException $ex) {  
      echo 'Failed to create new object, with error message: ' . $ex->getMessage();
    }

    $newState2 = new ParseObject("State");
    $newState2->set("state_name", "Colorado");
    try {
      $newState2->save();
      echo 'Object saved';
    } catch (ParseException $ex) {  
      echo 'Failed to create new object, with error message: ' . $ex->getMessage();
    }


    // Create City class and it's records
    $newCity1 = new ParseObject("City");
    // Define its attributes
    $newCity1->set("city_name", "Los Angeles");
    // To create a relation, pass the Parse Object as the field value
    $newCity1->set("state", $newState1);
    try {
      $newCity1->save();
      echo 'Object saved';
    } catch (ParseException $ex) {  
      echo 'Failed to create new object, with error message: ' . $ex->getMessage();
    }

    $newCity2 = new ParseObject("City");
    $newCity2->set("city_name", "Denver");
    $newCity2->set("state", $newState2);
    try {
      $newCity2->save();
      echo 'Object saved';
    } catch (ParseException $ex) {  
      echo 'Failed to create new object, with error message: ' . $ex->getMessage();
    }

Isn’t Parse SDK for PHP working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to PHP projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for PHP.

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
//In REST API, you first need to create the State Class, and define the attributes for each object:

//Creating State of California:

curl -X POST \
-H "X-Parse-Application-Id: APPLICATION_ID" \
-H "X-Parse-REST-API-Key: REST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"state_name":"California"}' \
https://parseapi.back4app.com/classes/State


//Creating State of Colorado:

curl -X POST \
-H "X-Parse-Application-Id: APPLICATION_ID" \
-H "X-Parse-REST-API-Key: REST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"state_name":"Colorado"}' \
https://parseapi.back4app.com/classes/State



//Then, go to your Dashboard to get the ObjetcId of each State. Replace them when creating the cities:

//Creating the city of Los Angeles with a pointer to California:

curl -X POST \
-H "X-Parse-Application-Id: APPLICATION_ID" \
-H "X-Parse-REST-API-Key: REST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"city_name":"Los Angeles","state": {"__type":"Pointer","className":"State","objectId":"ipetCqZX6l"}}' \
https://parseapi.back4app.com/classes/City


//Creating the city of Denver with a pointer to Colorado:

curl -X POST \
-H "X-Parse-Application-Id: APPLICATION_ID" \
-H "X-Parse-REST-API-Key: REST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"city_name":"Denver","state": {"__type":"Pointer","className":"State","objectId":"myhE1D0w3D"}}' \
https://parseapi.back4app.com/classes/City

If you have a custom Parse Server URL, replace the default (parseapi.back4app.com) to yours.

Isn’t Parse SDK for REST API working properly? Make sure you have installed it correctly by checking the official Parse Documentation regarding Parse SDK for REST API.

The code sample won’t work as expected if you haven’t installed Parse SDK correctly for the technology of your project.

Step 2 - Query relational data objects

Now that you have created the classes and its respective objects, let’s perform two different relational queries.
We will first look for cities that are localized in a certain state by using the Parse.Query.equalTo method. In this example, let’s search for all the cities that are in California State.
The second relational query, will retrieve every State object that is related to any City object, simulating an SQL JOIN query. For instance, we will retrieve every city that has a defined pointer to any State.

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
//Initialize Parse
Parse.initialize('YOUR_APP_ID_HERE','YOUR_JAVASCRIPT_KEY_HERE');
Parse.serverURL = 'https://parseapi.back4app.com/';

async function relationalQueries1() {

  let state = null;
  // Create Parse Query and get object by state_name
  const stateObject = new Parse.Query("State");
  stateObject.equalTo("state_name", "California");
  try {
    state = await stateObject.first();
  } catch (error) {
    console.log(`Failed to query object: ${error.message}`);
    return false;
  }

  // Query City class objects that are related to State of Califonia
  const cities = new Parse.Query("City");
  cities.equalTo("state", state);
  try {
    let results = await cities.find();
    for (let city of results) {
      console.log(`The city of ${city.get("city_name")}, with objectId: ${city.id}, belongs to the State of ${city.get("state").get("state_name")}.`);
    }
  } catch (error) {
    console.log(`Failed to query object: ${error.message}`);
    return false;
  }
}

async function relationalQueries2() {  
  // Create two queries that will interact with each other

  // Query State class
  const innerQueryState = new Parse.Query("State");
  // Query City class
  const outerQueryCity = new Parse.Query("City");

  // Match the State query by the "state" property
  outerQueryCity.matchesQuery("state", innerQueryState);
  // Include the "state" property so we can have the content of the State object as well
  outerQueryCity.include("state");
  try {
    let outerQueryResults = await outerQueryCity.find();
    for (let city of outerQueryResults) {
      console.log(`The city of ${city.get("city_name")} has a pointer to the state of ${city.get("state").get("state_name")}`);
    }
  } catch (error) {
    console.log(`Failed to query object: ${error.message}`);
    return false;
  }
}
}

Isn’t Parse SDK for JavaScript working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to JavaScript projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for JavaScript.

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
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //First query example:

        ParseObject state = null;
        // Create Parse Query and get object by state_name
        ParseQuery<ParseObject> stateObject = new ParseQuery<>("State");
        stateObject.whereEqualTo("state_name", "California");
        try {
            state = stateObject.getFirst();
        } catch (ParseException e) {
            e.printStackTrace();
        }

        // Query City class objects that are related to State of Califonia
        ParseQuery<ParseObject> cities = new ParseQuery<>("City");
        cities.whereEqualTo("state", state);
        // Include the "State" property so we can have the content of the State object as well
        cities.include("state");
        cities.findInBackground(new FindCallback<ParseObject>() {
            public void done(List<ParseObject> results, ParseException e) {
                if (e == null) {
                    for (ParseObject city : results) {
                        Log.d("msg", "The city of " + city.get("city_name") + ", with objectId: " + city.getObjectId() + ", belongs to the State of " + city.getParseObject("state").get("state_name"));
                    }
                } else {
                    Log.d("record", "Error: " + e.getMessage());
                }
            }
        });

        //Second query example:

        // Create two queries that will interact with each other
        // Query State class
        ParseQuery<ParseObject> innerQueryState = ParseQuery.getQuery("State");
        // Query City class
        ParseQuery<ParseObject> outerQueryCity = ParseQuery.getQuery("City");

        // Match the State query by the "state" property
        outerQueryCity.whereMatchesQuery("state", innerQueryState);
        // Include the "state" property so we can have the content of the State object as well
        outerQueryCity.include("state");

        outerQueryCity.findInBackground(new FindCallback<ParseObject>() {
            public void done(List<ParseObject> outerQueryResults, ParseException e) {
                if (e == null) {
                    for (ParseObject city : outerQueryResults) {
                        Log.d("msg", "The city of " + city.get("city_name") + " has a pointer to the state of " + city.getParseObject("state").get("state_name"));
                    }
                } else {
                    Log.d("record", "Error: " + e.getMessage());
                }
            }
        });
    }
}

Isn’t Parse SDK for Android working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to Android projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for Android.

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 {
  //Initialize Parse
  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);

  relationalQueries1();
  relationalQueries2();
}

void relationalQueries1() async{

  // Create Parse Query and get object by state_name
    final QueryBuilder<ParseObject> stateObject =
        QueryBuilder<ParseObject>(ParseObject('State'));

    stateObject.whereEqualTo('state_name', 'California');

    final ParseResponse stateResponse = await stateObject.query();
    if (!stateResponse.success) {
      return;
    }
    final state = stateResponse.results?.first as ParseObject;
    print(state);

  // Query City class objects that are related to State of Califonia
	  final QueryBuilder<ParseObject> cities =
        QueryBuilder<ParseObject>(ParseObject('City'));

  cities.whereEqualTo('state', state);
  cities.includeObject(['state']);

  final ParseResponse citiesResponse = await cities.query();
  if (!citiesResponse.success) {
    return;
  }

  for (var city in citiesResponse.results as List<ParseObject>) {
    
    print('The city of ${city.get('city_name')}, with objectId: ${city.objectId}, belongs to the state of ${city.get('state').get('state_name')}.');
  }
}

void relationalQueries2() async{
  // Create two queries that will interact with each other

  // Query State class
    final QueryBuilder<ParseObject> innerQueryState =
        QueryBuilder<ParseObject>(ParseObject('State'));

  // Query City class
    final QueryBuilder<ParseObject> outerQueryCity =
        QueryBuilder<ParseObject>(ParseObject('City'));

  // Match the State query by the "state" property
    outerQueryCity.whereMatchesQuery('state', innerQueryState);

  // Include the "state" property so we can have the content of the State object as well
    outerQueryCity.includeObject(['state']);

    final ParseResponse outerQueryResults = await outerQueryCity.query();
    if (!outerQueryResults.success) {
      return;
    }

    for (var city in outerQueryResults.results as List<ParseObject>) {
      
      print('The city of ${city.get('city_name')} has a pointer to the state of ${city.get('state').get('state_name')}.');
    }
}

Isn’t Parse SDK for Flutter working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to Flutter projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for Flutter.


Isn’t Parse SDK for iOS working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to iOS Swift and iOS ObjC projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for iOS.

1

Isn’t Parse SDK for .NET working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to .NET projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for .NET.

1

Isn’t Parse SDK for Unity working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to Unity projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for Unity.

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
//Initialize Parse
ParseClient::initialize("YOUR_APP_ID_HERE", "YOUR_REST_KEY_HERE", "YOUR_MASTER_KEY_HERE");
ParseClient::setServerURL('https://parseapi.back4app.com','/');

//First query example:
    
    // Create Parse Query and get object by state_name
    $stateObject = new ParseQuery("State");
    $stateObject->equalTo("state_name", "California");
    try{
        $state = $stateObject->first();
    } catch (ParseException $ex) {
        echo 'Failed to query object: ' . $ex->getMessage();
    }
    
    // Query City class objects that are related to State of Califonia
    $cities = new ParseQuery("City");
    $cities->equalTo("state", $state);
    $cities->includeKey("state");
    try{
        $results = $cities->find();
        for ($i = 0; $i < count($results); $i++) { 
            $city = $results[$i];
            echo "The city of " . $city->get("city_name") . ", with objectId " . $city->getObjectId() . ", belongs to the State of " . $city->get("state")->get("state_name") . ".<br/>";
        }
    } catch (ParseException $ex) {
       echo "Failed to query object: " . $ex->getMessage();
    }

    //Second query example:

    // Create two queries that will interact with each other

    // Query State class
    $innerQueryState = new ParseQuery("State");
    // Query City class
    $innerQueryState->exists("state_name");
    $outerQueryCity = new ParseQuery("City");

    // Match the State query by the "state" property
    $outerQueryCity->matchesQuery("state", $innerQueryState);
    // Include the "state" property so we can have the content of the State object as well
    $outerQueryCity->includeKey("state");
    try{
        $outerQueryResults = $outerQueryCity->find();
        for ($i = 0; $i < count($outerQueryResults); $i++) { 
            $city = $outerQueryResults[$i];
            echo "The city of " . $city->get("city_name") . " has a pointer to the State of ". $city->get("state")->get("state_name") . ".<br/>"; 
        }
    } catch (ParseException $ex) {
        echo "Failed to query object: " . $ex->getMessage();
    }

Isn’t Parse SDK for PHP working properly? Make sure you have installed it correctly by checking the complete Install Parse SDK guide to PHP projects. Also, feel free to check the official Parse Documentation regarding Parse SDK for PHP.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//relationalQuery1 - Reading all the cities in the State of Califonia:

curl -X GET \
-H "X-Parse-Application-Id: APPLICATION_ID" \
-H "X-Parse-REST-API-Key: REST_API_KEY" \
-G \
--data-urlencode 'where={"state":{"__type":"Pointer","className":"State","objectId":"ipetCqZX6l"}}' \
https://parseapi.back4app.com/parse/classes/City


//relationalQuery2 - Reading all the cities that have a defined pointer to the State class:

curl -X GET \
-H "X-Parse-Application-Id: APPLICATION_ID" \
-H "X-Parse-REST-API-Key: REST_API_KEY" \
-G \
--data-urlencode 'where={"state":{"$inQuery":{"where":{"state_name":{"$exists":true}},"className":"State"}}}' \
--data-urlencode 'include=state' \
https://parseapi.back4app.com/parse/classes/City

If you have a custom Parse Server URL, replace the default (parseapi.back4app.com) to yours.

Isn’t Parse SDK for REST API working properly? Make sure you have installed it correctly by checking the official Parse Documentation regarding Parse SDK for REST API.

What to do Next?

Now you can keep exploring Cloud Functions on your prefered technology or explore and also learn how to use cloud functions to make integrations, unit tests and more.

Conclusion

At this point, you have learned how to perform basic relational queries with Parse.Objects using Parse SDK. If you want to perform more advanced queries you can go through our specific guides for each Parse SDK, such as the React Native JOIN queries guide and the React relational queries guide.