21

I'm building an Android app with the Realm database.

I have a RealmObject subclass called Article which has an id field (it's and int and also a @PrimaryKey). I would like to pass to a query a list of ints (a Set, int[], or whatever) of article id's and retrieve only those articles.

In SQL would be like this:

SELECT *
FROM `table`
where ID in (5263, 5625, 5628, 5621) 

I've seen it's possible to do this in iOS in this StackOverflow question.

How can I do this in Android? Thanks!

Edit: Just to inform, I also asked this on the GitHub repo here.

Community
  • 1
  • 1
Albert Vila Calvo
  • 15,298
  • 6
  • 62
  • 73

5 Answers5

25

Update:

Realm 1.2.0 has added RealmQuery.in() for a comparison against multiple values. The documentation details all the available overloads. This one is the method we can use if our ids are Integers:

public RealmQuery<E> in(String fieldName, Integer[] values)

Original answer:

The answer from @ChristianMelchior returns all articles if the list of ids is empty. I want it to return an empty RealmResults<Article>. That's what I've ended up doing:

Set<Integer> articleIds = this.getArticleIds();
RealmQuery<Article> query = realm.where(Article.class);
if (articleIds.size() == 0) {
    // We want to return an empty list if the list of ids is empty. 
    // Just use alwaysFalse
    query = query.alwaysFalse();
} else {
    int i = 0;
    for (int id : articleIds) {
        // The or() operator requires left hand and right hand elements. 
        // If articleIds had only one element then it would crash with
        // "Missing right-hand side of OR"
        if (i++ > 0) {
            query = query.or();
        }
        query = query.equalTo("id", id);
    }
}
return query.findAll();
Albert Vila Calvo
  • 15,298
  • 6
  • 62
  • 73
  • 2
    That awkward moment when you answer is better than the one from the guy that works at Realm. Thanks, I thought of making something similar to this, but I was hoping that Realm already had some way of doing it. Apparently not ... – AndreiBogdan May 10 '16 at 17:36
  • you can simplify the code removing the i, just by using ```for(int pos = 0; pos < articleIds.size();pos++)``` and using ```if(pos >0) ...``` of course the result will be the same, you just save the int i creation and the int id creation(it create new one for each articleId), just saying, cuz everybody is freaking out about "memory leaks" so... each bit can matters ^^ – user2582318 Aug 24 '16 at 17:24
4

Now realm v 1.2.0 support RealmQuery.in() for a comparison against multiple values.

Albert Vila Calvo
  • 15,298
  • 6
  • 62
  • 73
mouness2020
  • 241
  • 3
  • 8
3

The Realm Java API's doesn't support this yet unfortunately. You can follow the feature request here https://github.com/realm/realm-java/issues/841

The current work-around would be to build up the query yourself in a for-loop:

RealmResults<Article> articles = realm.allObjects(Article.class);
RealmQuery q = articles.where();
for (int id : ids) {
    q = q.equalTo("id", id);
}
RealmResults<Article> filteredArticles = q.findAll();
Christian Melchior
  • 19,978
  • 5
  • 62
  • 53
  • Thanks @ChristianMelchior. The problem with this answer is that it returns all the articles if the list of ids is empty. In my opinion it should return an empty `RealmResults
    `. I could add an `if` statement and check if `ids` is empty, but I haven't found any way to create an empty `RealmResults
    `. Do you know how?
    – Albert Vila Calvo Nov 13 '15 at 12:02
  • Depending on what you are doing with the RealmResults. It implements the List interface so you could just create an empty ArrayList and use that instead. Currently there is no way of manually creating an empty RealmResults. – Christian Melchior Nov 13 '15 at 12:06
  • 3
    2 things: the method `equalsTo()` (with an 's') does not exist (at least not on 0.84.1), and your code works only when there is one element on the list of ids (you need an `or()`). Thanks anyway! – Albert Vila Calvo Nov 13 '15 at 13:05
  • Please update this answer: since realm v 1.2.0 support it's possible to do a RealmQuery.in(). – Anis LOUNIS aka AnixPasBesoin Jan 18 '17 at 13:34
2

This is the way Realm does it since 1.2.0:

public RealmQuery<E> in(String fieldName, String[] values) {
    if (values == null || values.length == 0) {
        throw new IllegalArgumentException(EMPTY_VALUES);
    }
    beginGroup().equalTo(fieldName, values[0]);
    for (int i = 1; i < values.length; i++) {
        or().equalTo(fieldName, values[i]);
    }
    return endGroup();
}

Previously this is how I did it

Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
1

I just came across this post and I thought I could throw in my 2 cents on this. As much as I appreciate Christian Melchior and his answers I think in this case his answer is not working (at least in the current version).

I prefer to do it like this - I personally think it's more readable than Albert Vila's answer:

List<String> listOfIds = [..];
RealmQuery<SomeClass> query = realm.where(SomeClass.class);

boolean first = true;
for (String id : listOfIds) {
    if (!first) {
        query.or();
    } else {
        first = false;
    }
    query.equalTo("id", id);
}
RealmResults<SomeClass> results = query.findAll();
Langusten Gustel
  • 10,917
  • 9
  • 46
  • 59