Skip to content

Retrieving JSON Data

JSON values are stored in database columns of type JSON. The data retrieval mechanism for JSON values is the same as for any other data stored in Backendless database. You can use the data retrieval API to retrieve objects from the Backendless database. Data in the JSON columns is returned to the client application as either a strongly-typed object or as an instance of java.util.Map.. Consider the example below:

Suppose the database stores objects in the Person data table. The table declares the profile column of type JSON. The column contains JSON values in the following format:

{
  "age": 55,
  "name": "Bob",
  "address": {
    "city": "Los Angeles",
    "state": "California",
    "street": "123 Santa Monica Blvd."
  },
  "lastname": "Smith",
  "favoriteColors": [
    "Blue", "Red"
  ],
  "favoriteNumbers": [
    13, 21, 88
  ]
}

As you can see the sample JSON value above exhibits the following "qualities":

  • literal string and numeric values - age, name and lastname keys.
  • an array consisting of strings - favoriteColors
  • an array consisting of numbers - favoriteNumbers
  • an enclosed JSON object in the address key.

The JSON values and the Person objects may appear as shown below in the database:

sample-json-database

Suppose the client application needs to retrieve both Person objects and the corresponding profile values as instances of java.util.Map.. This can be accomplished with the following code:

Backendless.Data.of( "Person" ).findById( OBJECT_ID, new AsyncCallback<Map>()
{
    @Override
    public void handleResponse( Map person )
    {
        Map profile = (Map) person.get( "profile" );
        Log.d( "MYAPP", "Name " + profile.get( "name" ) );
        Log.d( "MYAPP", "Last name " + profile.get( "lastname" ) );
        Log.d( "MYAPP", "Age " + profile.get( "age" ) );
        Log.d( "MYAPP", "Favorite numbers " + Arrays.toString( (Integer[]) profile.get( "favoriteNumbers" ) ) );
        Log.d( "MYAPP", "Favorite colors " + Arrays.toString( (String[]) profile.get( "favoriteColors" ) ) );

        Map address = (Map) profile.get( "address" );
        Log.d( "MYAPP", "Street " + address.get( "street" ) );
        Log.d( "MYAPP", "City " + address.get( "city" ) );
        Log.d( "MYAPP", "State " + address.get( "state" ) );
    }

    @Override
    public void handleFault( BackendlessFault fault )
    {

    }
} );
Backendless.Data.of("Person").findById(OBJECT_ID, object : AsyncCallback<Map<*, *>> {
   override fun handleResponse(person: Map<*, *>) {
       val profile = person["profile"] as Map<*, *>
       Log.d("MYAPP", "Name ${profile["name"]}")
       Log.d("MYAPP", "Last name ${profile["lastname"]}")
       Log.d("MYAPP", "Age ${profile["age"]}")
       Log.d("MYAPP", "Favorite numbers ${(profile["favoriteNumbers"] as Array<Int>).contentToString()}")
       Log.d("MYAPP", "Favorite colors ${(profile["favoriteColors"] as Array<String>).contentToString()}")
       val address = profile["address"] as Map<*, *>
       Log.d("MYAPP", "Street ${address["street"]}")
       Log.d("MYAPP", "City ${address["city"]}")
       Log.d("MYAPP", "State ${address["state"]}")
   }

   override fun handleFault(fault: BackendlessFault) {
       Log.e("MYAPP", fault.message)
   }
})

The code produces the following log output:

Name Bob
Last name Smith
Age 55
Favorite numbers [13, 21, 88]
Favorite colors [Blue, Red]
Street 123 Santa Monica Blvd.
City Los Angeles
State California

As you can see, the entire JSON structure is converted to a Java Map with all the key/value pairs becoming corresponding entries in the returned object.

Your application may use an alternative approach - representing objects in the Backendless database with strongly-typed classes. In the context of the example above, this means you will have the Person class defined in your application. But then there is a question of what data type to use for the profile property? In this case, you have a choice for how to represent the JSON values. You can use either strongly-typed objects or the java.util.Mapapproach described above. See the example below:

Java:

Person class with "profile" defined as java.util.Map:

package com.company;

import java.util.Map;

public class Person
{
  private Map profile;

  public Map getProfile()
  {
    return profile;
  }

  public void setProfile( Map profile )
  {
    this.profile = profile;
  }
}
Code to retrieve Person with profile:
Backendless.Data.of( Person.class ).findById( OBJECT_ID, new AsyncCallback<Person>()
{
   @Override
   public void handleResponse( Person person )
   {
       Map profile = person.getProfile();
       Log.d( TAG, "Name " + profile.get( "name" ) );
       Log.d( TAG, "Last name " + profile.get( "lastname" ) );
       Log.d( TAG, "Age " + profile.get( "age" ) );
       Log.d( TAG, "Favorite numbers " + Arrays.toString( (Integer[]) profile.get( "favoriteNumbers" ) ) );
       Log.d( TAG, "Favorite colors " + Arrays.toString( (String[]) profile.get( "favoriteColors" ) ) );

       Map address = (Map) profile.get( "address" );
       Log.d( TAG, "Street " + address.get( "street" ) );
       Log.d( TAG, "City " + address.get( "city" ) );
       Log.d( TAG, "State " + address.get( "state" ) );
   }

   @Override
   public void handleFault( BackendlessFault fault )
   {
   }
} );

Person class with "profile" defined as a custom class. The class uses public fields for brevity - alternatively use get/set methods):

public class Person {
   public Profile profile;
}
Profile class (uses public fields for brevity - alternatively use get/set methods):
public class Profile {
   public String age;
   public String name;
   public String lastname;
   public Address address;
   public String[] favoriteColors;
   public int[] favoriteNumbers;
}
Address class (uses public fields for brevity - alternatively use get/set methods):
public class Address {
   public String city;
   public String state;
   public String street;
}
Code to retrieve Person with profile:
Backendless.Data.of( Person.class ).findById( OBJECT_ID, new AsyncCallback<Person>()
{
   @Override
   public void handleResponse( Person person )
   {
       Profile profile = person.profile;
       Log.d( TAG, "Name " + profile.name );
       Log.d( TAG, "Last name " + profile.lastname );
       Log.d( TAG, "Age " + profile.age );
       Log.d( TAG, "Favorite numbers " + Arrays.toString( profile.favoriteNumbers ) );
       Log.d( TAG, "Favorite colors " + Arrays.toString( profile.favoriteColors ) );

       Address address = profile.address;
       Log.d( TAG, "Street " + address.street);
       Log.d( TAG, "City " + address.city);
       Log.d( TAG, "State " + address.state);
   }

   @Override
   public void handleFault( BackendlessFault fault )
   {
       Log.e(TAG, fault.getMessage());
   }
} );

Kotlin:

Person class with "profile" defined as java.util.Map:

class Person {
   var profile: Map<*, *>? = null
}
Code to retrieve Person with profile:
Backendless.Data.of(Person::class.java).findById(OBJECT_ID, object : AsyncCallback<Person> {
   override fun handleResponse(person: Person) {
       val profile = person.profile!!
       Log.d("MYAPP", "Name ${profile["name"]}")
       Log.d("MYAPP", "Last name ${profile["lastname"]}")
       Log.d("MYAPP", "Age ${profile["age"]}")
       Log.d("MYAPP", "Favorite numbers ${(profile["favoriteNumbers"] as Array<Int>).contentToString()}")
       Log.d("MYAPP", "Favorite colors ${(profile["favoriteColors"] as Array<String>).contentToString()}")
       val address = profile["address"] as Map<*, *>
       Log.d("MYAPP", "Street ${address["street"]}")
       Log.d("MYAPP", "City ${address["city"]}")
       Log.d("MYAPP", "State ${address["state"]}")
   }

   override fun handleFault(fault: BackendlessFault) {
       Log.e("MYAPP", fault.message)
   }
})

Person class with "profile" defined as a custom class.

class Person {
   var profile: Profile? = null
}
Profile class:
class Profile {
   var age: String? = null
   var name: String? = null
   var lastname: String? = null
   var address: Address? = null
   var favoriteColors: Array<String>? = null
   var favoriteNumbers: Array<Int>? = null
}
Address class:
class Address {
   var city: String? = null
   var state: String? = null
   var street: String? = null
}
Code to retrieve Person with profile:
Backendless.Data.of(Person::class.java).findById(OBJECT_ID, object : AsyncCallback<Person> {
   override fun handleResponse(person: Person) {
       val profile = person.profile!!
       Log.d("MYAPP", "Name ${profile.name}")
       Log.d("MYAPP", "Last name ${profile.lastname}")
       Log.d("MYAPP", "Age ${profile.age}")
       Log.d("MYAPP", "Favorite numbers ${(profile.favoriteNumbers as Array<Int>).contentToString()}")
       Log.d("MYAPP", "Favorite colors ${(profile.favoriteColors as Array<String>).contentToString()}")
       val address = profile.address!!
       Log.d("MYAPP", "Street ${address.street}")
       Log.d("MYAPP", "City ${address.city}")
       Log.d("MYAPP", "State ${address.state}")
   }

   override fun handleFault(fault: BackendlessFault) {
       Log.e("MYAPP", fault.message)
   }
})

In case when the JSON values are represented as strongly-typed classes, Backendless automatically adapts them to the instances of your classes. It is important to maintain the basic fidelity between the JSON types and the corresponding java types as shown below:

JSON Type
Java Type
string
java.lang.String
number
int or java.lang.Integer
boolean
boolean or java.lang.Boolean
object
custom class or java.util.Map
array
java.util.List
java.util.List<T>
int[]
String[]
boolean[]

Codeless Reference

Retrieving Object By objectId

data_retrieving_json_data

where:

Argument                Description
table name Name of the data table from where the object is retrieved.
object id Unique identifier of the object to retrieve.
relations Name of the related property to load. For example, if table employees has a relation column homeAddress pointing to an object in the Address table, the value of the parameter would be homeAddress. The syntax allows to add relations of relations. For example, if the same Address table has a relation country pointing to the Country table, then homeAddress.country would instruct the backend to load the related Country object.
relations depth Depth of the relations to include into the response.
properties Names of the properties/columns for which  to load the corresponding values.
exclude properties Names of the properties/columns that should not be included in the response.

Returns the object containing JSON data.

Consider the following records stored in the Person data table:

data_retrieving_json_data_3

Suppose you need to retrieve one object containing JSON values. The example below retrieves the record from the data table using the object Id value.

data_retrieving_json_data_1

After the Codeless logic runs, the server returns the object containing JSON values.

data_retrieving_json_data_2

Retrieving Multiple Objects

Consider the following records stored in the Person data table:

data_retrieving_json_data_3

Suppose you need to retrieve objects from the data table containing "New York" value in the "city" property and values greater than 20 in the "age" property. To achieve this, you need to use the following where clause condition:

profile->'$.age' > 20 and profile->'$.address.city' = 'New York'

For more information about retrieving objects using the where clause condition, refer to the JSON Query documentation.

The example below finds objects matching the where clause condition presented above.

data_retrieving_json_data_5

Important

For a detailed description of all input parameters see the Basic Object Retrieval topic of this guide.

After the Codeless logic runs, the operation returns two objects matching the specified where clause condition:

data_retrieving_json_data_4