Understanding Queries in Realm Java using Android Studio (PART 4)

in #utopian-io6 years ago

realm logo

Repository

https://github.com/realm/realm-java

What Will I Learn?

  1. You will learn about Queries in Realm
  • beginGeoup() and endGroud() predicates
  • not () predicate
  • sort() predicate

Requirements

  • An Integrated Development Environment(IDE) for building Android Application(e.g Android Studio, IntelliJ)
  • Android Device/Virtual Device.
  • Little Experience in working with Realm Java.
  • Java Programming Experience.
  • Of course, willingness to learn

Resources

Difficulty

  • Intermediate

Tutorial Duration - 30 - 35Mins

Tutorial Content

In Today's tutorial, we are going to continue learning about queries in Realm. The first,second and third part of this tutorial series can be found here, here and here respectively.

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 a single unicode character
  • * 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 :

  1. between() predicates takes three arguments, first the name of the object's field - e.g "age", secondly a lower bound and then lastly an upper bound e.g between("age", 5, 9) - this gives returns objects that their age field is between 5 and 9.
  2. greaterThan() predicates takes two arguments, first the field name and then the query integer e.g - greaterthan("age", 56) which returns objects that their age field's value is greater than 56
  3. lessThan() predicates takes the same arguments as the greaterThan() predicates e.g - lessThan("age", 20) which returns object that their age field value is less than 20.
  4. greaterThanOrEqualTo() predicates takes the same number of argument as specified above e.g greaterThanOrEqualTo("age", 30) which return objects that their age field has a value greater than or equal to 30.
  5. lessThanOrEqualTo() predicate takes the same number of argument as specified above e.g lessThanOrEqualTo("age", 75) which returns the objects that their age field value is less than or equal to 75.

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 beginGroup() and endGroup(), not() and sort() predicates.

In order to achieve this, we are going to modify the existing android application that we have developed in tutorials 1, 2, and 3.

Outline

  • Dependencied Used
  • Show predicates illustrations

Dependencies used

Please refer to the first tutorial for the dependencies used in this tutorial as no new dependencies have been added

Show predicates illustrations

In order to show illustrate the usage of today's predicates, the following modifications will be made:

  1. NumericQuery Fragment
    • In this fragment, we are going to be modifying our greaterThan() predicate section to include the beginGroup() and endGroup() predicate in our query.
    • We would also be modifying our lessThan() predicate code section to include the not() predicate in our query.
  2. DoubleNumericQuery Fragment
    • We would be including the sort() predicate in our between() predicate code section.

NumericFragment
In our NumericFragment we will be adding two new EditText to our layout file which we will be using to receive an email address and also an address of the objects we intend to query.

We will then make a query that will find Person objects that their age field is greater than the age entered by the user and that their email address field contains the email entered and also that their address field also contains the address entered.

For instance, we can say that we are looking for users that are older than 20 , have a gmail account and also live in Nigeria.

We are going to achieve this using the beginGroup() and endGroup() predicates which group predicates together and specifies the order of evaluation.

We will then use the not() predicate to negate the above query which will find Person objects that their age field is above the age entered and but their email field doesn't contain the email entered and their address field doesn't contain the address entered.

Add the following code to your NumericFragment layout file to include the two new EditText.
NB: The XML code below will only feature new additions to the layout file and other existing views will be indicated in comments - //

numeric_query_fragment.xml

//Root ScrollView
 //LinearLayout with vertical orientation
  //Single EditText age input
<EditText
android:id="@+id/query_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:inputType="textEmailAddress"
android:hint="Enter Email Contains" />

<EditText
android:id="@+id/query_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:inputType="text"
android:hint="Enter Address contains" />

//Go Button
 //Two TextView's

NumericQuery

In our NumericQuery Fragment, we are going to be learning the endGroup() and the beginGroup() and the not() predicates. They are used to include an implicit AND in our queries by grouping predicates together, the beginGroup() indicates where the grouping starts and the endGroup() indicates where the grouping ends.

After injecting our two new EditText using butterknife by placing our cursoir on the layout name inside the setContentView() method => alt + ins => Generate ButterKnife Injection and select the two new EditText as shown below:

butterKnife.PNG

Next, in our onClick() method of the GO button, we add the following codes :

@OnClick(R.id.go_btn)
    public void onViewClicked() {
String age = queryAge.getText().toString();
String email = queryEmail.getText().toString();
String address = queryAddress.getText().toString();

StringBuilder toDisplay = new StringBuilder();

if (!(age.isEmpty() && email.isEmpty() && address.isEmpty())) {
    RealmResults<Person> result = realm.where(Person.class)
            .greaterThan("age", Integer.valueOf(age))
            .beginGroup()
                .contains("email",email)
                .and()
                .contains("address",address)
            .endGroup()
            .findAll();

    toDisplay.append("beginGroup() - endGroup() Predicate\n\n");
    toDisplay.append("There are - " + result.size() + " Persons older than " + age + "that their emails contains "+email+" and their address contains "+address+"\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++;

    result = realm.where(Person.class)
                .greaterThan("age", Integer.valueOf(age))
                .not()
                .beginGroup()
                    .contains("email",email)
                    .and()
                    .contains("address",address)
                .endGroup()
                .findAll();

        toDisplay.append("not() Predicate\n\n");
        toDisplay.append("There are - " + result.size() + " Persons older than " + age +
        "that their emails doesn't contain "+email+" and their address doesn't contain "+address+"\n\n");

        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++;
        }
}

Code Explanation

  1. We get the value of the three EditText's and store in string variables - age, email and address.
  2. We declear a StringBuilder object - toDisplay
  3. We use an if statement to ensure that the age, email and address variables are not empty else we simply call the showToast() method with the argument -"No Field can be Empty".
  4. We create a RealmResult object - result and then we use the greaterThan() predicate with the where statment specifying the Person class and then using the beginGroup() predicate to start an implicit and and then use the contains() predictae specifying the email field and passing the email as the second argument, then we add the and() statement and then add another contains() predicate specifying the address field as the query field and using the address as the second argument.
    • In order words, the above statement searches for Person objects that their age field is greater than 20 AND their email address field contains the email entered by the user AND their address field contains the address entered by the user.
  5. We append the text - beginGroup() - endGroup() Predicate and also append the size of the objects that are returned by the query by - result.size()
  6. We then use a while loop to loop through the objects that match our query and then display the details of each object.
    • name : result.get(i).name
    • phone number : result.get(i).phone_number
    • email : result.get(i).email
    • address : result.get(i).address
    • age : result.get(i).age
  7. We then display our result in our TextView - resultTv.setText(toDisplay.toString());
  • The same explanation goes for the not() predicate which negates the beginGroup() and endGroup() predicates meaning it does the opposite.

DoubleNumericQuery
In our DoubleNumericQuery Fragment, we are going to illustrate the usage of the sort() predicates, as the name implies the sort() predicates sorts the result of a query which takes two arguments:

  1. The first argument is the field you want to sort the result by.
  2. An optional Sort.DESCENDING or Sort.ASCENDING argument
    NB: By default, the sort() sorts in an ascending order.

We are going to be sorting the RealmResults object - results

In our DoubleNumericQuery Fragment java class file, in our onClick() method of our GO button, we will edit it to the following :

@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))
            .findAll();

    toDisplay.append("between() Predicate\n\n");
    toDisplay.append("There are - " + result.size() + " Persons between " + age + " and "+age2+"\n\n");

    result = result.sort("age");
    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++;
    }

    result = result.sort("age",io.realm.Sort.DESCENDING);
    toDisplay.append("DESCENDING ORDER BY AGE\n\n");
    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

  1. We get the value of the two EditText's and store in string variables - age and age2.
  2. We declare a StringBuilder object - toDisplay
  3. We use an if statement to ensure that the age and age2 variables are not empty and also that the age2 variable is greater than the age variable else we simply call the showToast() method with the argument -"No Field can be Empty and First Age must be greater than Second Age".
  4. We create a RealmResult object - result and then we use the between() predicate with the where statement specifying the Person class and then setting the lower and upper bound values of the between() predicate to be age and age2.
  5. We append the text - between() predicate and also append the size of the objects that are returned by the query by - result.size() and append the age and age2 values.
  6. We then set the value of result to an ASCENDING sorted value of the result gotten by - result = result.sort("age"); where age is the field we sorted by.
  7. We append the text - ASCENDING ORDER BY AGE
  8. We then use a while loop to loop through the objects that match our query and then display the details of each object.
    • name : result.get(i).name
    • phone number : result.get(i).phone_number
    • email : result.get(i).email
    • address : result.get(i).address
    • age : result.get(i).age
  9. We then repeat the same steps inorder to sort the result object in a DESENDING order still using the age field.
    • here - result = result.sort("age",io.realm.Sort.DESCENDING); we initialze the result object to itself but sorted in DESENDING order
  10. We then display our result in our TextView - resultTv.setText(toDisplay.toString());

Application Execution

Sort:  

Hey @edetebenezer
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Thank you for your contribution.
While I liked the content of your contribution, I would still like to extend one advice for your upcoming contributions:

  • There is part of the text that should have a line break.

Looking forward to your upcoming tutorials. Good job!

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Thanks @portugalcoin for moderating my post and thanks for the tips also would definitely make improvements on subsequent contributions.

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.034
BTC 63475.77
ETH 3117.23
USDT 1.00
SBD 3.94