https://github.com/realm/realm-java
In Today's tutorial, we are going to continue learning about queries in Realm. Previous tutorial links can be found below :
Recap of Part 1
In part 1 of this tutorial, we looked at three predicates - contains(),beginsWith(),in() and we were able to understand this by creating an android application that demonstrates the uses of this predicates.
We learnt that predicates that the form of `predicateName("field","query string",OPTIONAL ARGUMENT);
e.g - contains("name","Edet Ebenezer",Case.SENSITIVE);
The above code checks if any object's name field contains the text - Edet Ebenezer without paying attention to the cases.
We also learned how to use the third optional argument for the predicates which are Case.INSENSITIVE and Case.SENSITIVE where the former ignores the case of the query string to the contents of the field specified and the latter doesn't ignore it.
Recap of Part 2
In the part two of this tutorial series, we looked at the - beginsWith(), endsWith(),like() predicates.
The beginsWith() predicate checks to ensure that an object's field begins with the query string passed as the second argument to it and then it also takes the optional third case argument - Case.SENSITIVE or Case.INSENSITIVE, while the endsWith() predicate does the opposite of the beginsWith() predicate where it checks to ensure that an object's field ends with the query string passed as the second argument to it, and it also takes the third optional case argument.
Meanwhile, the like() predicate performs a glob style wildcard matching with the following :
* matches 0 or more unicode characters.Recap of Part 3
In the part three of this series, we looked at the between(),greaterThan(),lessThan(),greaterThanOrEqualTo(),lessThanOrEqualTo() predicates.
We learned the following about the above predicates :
between("age", 5, 9) - this gives returns objects that their age field is between 5 and 9.greaterthan("age", 56) which returns objects that their age field's value is greater than 56greaterThan() predicates e.g - lessThan("age", 20) which returns object that their age field value is less than 20.greaterThanOrEqualTo("age", 30) which return objects that their age field has a value greater than or equal to 30.lessThanOrEqualTo("age", 75) which returns the objects that their age field value is less than or equal to 75.Recap of Part 4
In part 4 of this tutorial, we looked at three predicates namely :
beginGroup() and endGroup() predicate starts and ends a group of predicates and also specifies the order of evaluation - e.gRealmResults<Person> result = realm.where(Person.class)
.greaterThan("age", 15)
.beginGroup()
.contains("email","gmail.com")
.and()
.contains("address","Nigeria")
.endGroup()
.findAll();
The above query finds Person objects that are older than 15 and their email contains the words gmail.com AND their address contains the words Nigeria.
2.not() predicate negates a predicate - e.g
RealmResults<Person> result = realm.where(Person.class)
.greaterThan("age", 15)
.not()
.beginGroup()
.contains("email","gmail.com")
.and()
.contains("address","Nigeria")
.endGroup()
.findAll();
The above code does the opposite of the one before it meaning it queries for Person objects that are older than 15, but their emails don't contain the word - gmail.com and their address dont contain the word - Nigeria
3.sort() predicate is used to sort results of queries and it takes two arguments meanwhile it sorts by ASCENDING order by default -
- The field on which the sorting will be done.
- An optional sort parameter - Sort.ASCENDING or Sort.DESCENDING.
e.g result = result.sort("age",Sort.ASCENDING) or result = result.sort("age",Sort.DESCENDING)
Todays Tutorials
In today's tutorial, we are going to be learning about more query predicates in Realm, we are going to be learning about the distinct() predicate and also how to chain queries.
In order to achieve this, we are going to modify the existing android application that we have developed in tutorials 1 - 4.
Please refer to the first tutorial for the dependencies used in this tutorial as no new dependencies have been added
In order to show illustrate the usage of today's predicates, the following modifications will be made:
DoubleNumericQuery Fragment
NumericQuery Fragment
DoubleNumericQuery
Our DoubleNumericQuery Fragment formally accepted two inputs from the user - first and second age and then we used the between() predicate to find Person objects that their age field value falls between this range (first age - second age).
We will then be using the distinct() predicate together with the between() predicate.
The distinct() predicate returns only unique values based on the field specified, meaning if we have a realm database of four objects having two objects with the same age field value and we specify the age field in our distinct() predicate, the RealmResult list will, therefore, return 3 objects rather than four.
To illustrate this, we will be modifying our persons.json file to be this -
NB : Below code will only contain alterations, other objects will be specified after comments - //
[
{
"name": "Ebenezer Edet",
"address": "Garki Abuja",
"phone_number": 242424,
"email": "[email protected]",
"age": 30
},
//Six other json objects
{
"name":"Ebenezer Edet",
"address":"Lugbe Abuja",
"phone_number":345678,
"email":"[email protected]",
"age":45
},
//Two other json objects
]
In our DoubleNumericQuery java class file, inside our onClick() method for our GO button, we edit the codes as below -
@OnClick(R.id.go_btn)
public void onViewClicked() {
String age = queryName.getText().toString();
String age2 = queryName2.getText().toString();
StringBuilder toDisplay = new StringBuilder();
if ((!(age.isEmpty() && age2.isEmpty()))&& (Integer.valueOf(age2) > Integer.valueOf(age))) {
RealmResults<Person> result = realm.where(Person.class)
.between("age", Integer.valueOf(age),Integer.valueOf(age2))
.distinct("name")
.findAll();
toDisplay.append("between() Predicate\n\n");
toDisplay.append("There are - " + result.size() + " Persons between " + age + " and "+age2+"\n\n");
result = result.sort("age", Sort.ASCENDING);
toDisplay.append("ASCENDING ORDER BY AGE\n\n");
int i = 0;
while (i < result.size()) {
toDisplay.append(result.get(i).name + " with phone number : " + result.get(i).phone_number + " email : " + result.get(i).email + " Address :" + result.get(i).address + " and age : "+ result.get(i).age +"\n\n\n");
i++;
}
resultTv.setText(toDisplay.toString());
}
else
showToast("No Field can be Empty and First Age must be greater than Second Age");
Code Explanation
distinct() predicate specifying the name field as the argument which means that we only want unique names to be returned and duplicate names ignored.result = result.sort("age"); where age is the field we sorted by.result = result.sort("age",io.realm.Sort.DESCENDING); we initialze the result object to itself but sorted in DESENDING orderresultTv.setText(toDisplay.toString());NumericQuery
In the NumericQuery fragment class, we are going to be editting our lessThan() predicate code section and demostrate query chaining which allows us to run additional queries on result sets.
For instance, if you want to get all objects that are younger than 50 and then you want to get a specific Person in that result set - e.g a 30 old person or one that his address contains - Nigeria, you will then need to chain the queries as explained below.
NB: Query chains are built on RealmResults objects and not RealmQuery object.
In the onClick() method of the GO button , edit to contain the following code
@OnClick(R.id.go_btn)
public void onViewClicked() {
String age = queryAge.getText().toString();
String specificAge = queryEmail.getText().toString();
StringBuilder toDisplay = new StringBuilder();
if (!(age.isEmpty() && specificAge.isEmpty())){
RealmResults<Person> result = realm.where(Person.class)
.lessThan("age",Integer.valueOf(age))
.findAll();
toDisplay.append("lessThan() Predicate\n\n");
toDisplay.append("There are - " + result.size() + " Persons younger than " + age + "\n\n");
toDisplay.append("These are the objects matching the lessThan() predicate");
int i = 0;
while (i < result.size()) {
toDisplay.append(result.get(i).name + " with phone number : " + result.get(i).phone_number + " email : " + result.get(i).email + " Address :" + result.get(i).address + " and age : "+ result.get(i).age +"\n\n\n");
i++;
}
toDisplay.append("Query Chain Result\n\n");
Person singlePerson = result.where().equalTo("age",Integer.valueOf(specificAge)).findFirst();
if(!(singlePerson == null)){
toDisplay.append("This is the object returned after query chaining");
toDisplay.append(singlePerson.name + " with phone number : " + singlePerson.phone_number + " email : " + singlePerson.email + " Address :" + singlePerson.address + " and age : "+ singlePerson.age +"\n\n\n");
}
else
toDisplay.append("No Person in our result set has an age of "+specificAge);
resultTv.setText(toDisplay.toString());
}
else
showToast("No Field can't be empty");
Code Explanation
RealmResult variable - result and the Person class is specified joined with the lessThan() predicate and the age entered by the user is the second query.result.size().Person objects that meet our query using a while loop and the details are gotten by :
Person object - singlePerson using the equalTo() predicate specying the age field and passing specificAge as the second argument and finally we specify that we want the first object that matches our query with - findFirst() method.
RealmResult list of objects that have their age field greater than the entered age - e.g 30 and then will finally pick one object that has its age equal to the specificAge variable entered by the user and any object that first matches this condition is returned.singlePerson is null because there is a possiblity that no Person object matches our query and if none meets the condition, we append the text - "No Person in our result set has an age of "+specificAge" to the toDisplay object inside our else statment.resultTv.setText(toDisplay.toString());https://github.com/generalkolo/Realm-JSON/tree/master/Realm%20Relationships