4

I need to find customers from Realm Db based on first and last name. Currently, I have a query like this:

RealmResults<CustomerModel> results = realm
            .where(CustomerModel.class)
            .or()
            .contains("firstname", input, Case.INSENSITIVE)
            .or()
            .contains("lastname", input, Case.INSENSITIVE)
            .or()
            .contains("addresses.street", input, Case.INSENSITIVE)
            .or()
            .contains("addresses.city", input, Case.INSENSITIVE)
            .or()
            .contains("addresses.postcode", input, Case.INSENSITIVE)
            .findAllSorted("customerLocalId", Sort.DESCENDING);

This does not work properly since I have OR between first and last name.

So, if I want to find user named John Doe, it wont find it, but if I type only John it will find it.

How I can solve this?

Zookey
  • 2,637
  • 13
  • 46
  • 80

2 Answers2

2

Why not split across white space?

String filter = input.trim().replaceAll("\\s+", " ");
String[] tokens = filter.split(" ");
RealmQuery<CustomerModel> query = realm.where(CustomerModel.class);

for(int i = 0, size = tokens.length; i < size; i++) {
    String token = tokens[i];
    if(i != 0) {
        query.or();
    }
    query.contains("firstname", token, Case.INSENSITIVE)
        .or()
        .contains("lastname", token, Case.INSENSITIVE)
        .or()
        .contains("addresses.street", token, Case.INSENSITIVE)
        .or()
        .contains("addresses.city", token, Case.INSENSITIVE)
        .or()
        .contains("addresses.postcode", token, Case.INSENSITIVE)        
}

RealmResults<CustomerModel> results = query
        .findAllSorted("customerLocalId", Sort.DESCENDING);
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • It seems that it does not work. I just tried and the result is same. – Zookey Jan 09 '19 at 09:23
  • I have tried without or between firstname and lastname, but that does not work at all. – Zookey Jan 09 '19 at 09:30
  • Hmm maybe I messed up the `replaceAll`. I initially had `" +"` in the answer, but replaced it with `\\s+` and I probably shouldn't have? can you check that – EpicPandaForce Jan 09 '19 at 09:33
  • I have tried both, but the result is same. Tokens array has 2 items, both "John" and "Doe", but it seems that it can not find an item from DB that has John as firstname and Doe as lastname. So, I guess there is a problem query logic. – Zookey Jan 09 '19 at 09:39
  • I have edited my questions, please take look when you have time. Do you have some better idea? – Zookey Jan 09 '19 at 10:07
  • What version of Realm are you using? https://github.com/realm/realm-core/pull/2953 this was fixed a while ago but it's somewhere 5.x+ – EpicPandaForce Jan 09 '19 at 10:34
  • It is a legacy project, so Realm version is 3.7.2. If I upgrade should it solve the problem? – Zookey Jan 09 '19 at 12:34
  • Any version that is newer than Realm-Java 5.0.1 contains the fix. Please beware that there were ***two*** major versions inbetween, so refer to https://stackoverflow.com/questions/39971209/upgrade-realm-in-an-android-project – EpicPandaForce Jan 09 '19 at 12:37
  • Updated to the 5.8.0 version, but it still does not work with your code. :( – Zookey Jan 09 '19 at 12:54
  • Omg. I did the splitting but then ended up not using the splitted array. I'm stupid :( – EpicPandaForce Jan 09 '19 at 13:18
  • BTW if you are updating to `Realm 5.x`, then IF you are using `RealmRecyclerViewAdapter`, you need to update to `realm-android-adapters:3.0.0`+ – EpicPandaForce Jan 09 '19 at 13:21
  • I'm not quite sure it'll give you the result you want, because it'll add a buch of `contains` merged with `or` but you sat you want to get customers with complete name `John Doe`, consider my answer to check if it's what you want. If you are not sure about the `input` you can use EpicPandaForce answer and combine it with `group` – Maelig Jan 11 '19 at 14:47
  • @maelig his problem was that he wanted to tokenize the string and match one token against one field, and one token against another field. Then I managed to split the string and not use it at all for like 3 days ;) derp – EpicPandaForce Jan 11 '19 at 15:38
0

You need to use group : https://realm.io/docs/java/latest/#logical-operators

RealmResults<CustomerModel> results = realm
        .where(CustomerModel.class)
        .beginGroup()
        .contains("firstname", input, Case.INSENSITIVE)
        .contains("lastname", input, Case.INSENSITIVE)
        .endGroup()
        .or()
        .contains("addresses.street", input, Case.INSENSITIVE)
        .or()
        .contains("addresses.city", input, Case.INSENSITIVE)
        .or()
        .contains("addresses.postcode", input, Case.INSENSITIVE)
        .findAllSorted("customerLocalId", Sort.DESCENDING);
Maelig
  • 2,046
  • 4
  • 24
  • 49