New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LIMIT #544

Closed
gjcameron opened this Issue Nov 9, 2014 · 28 comments

Comments

Projects
None yet
@gjcameron

gjcameron commented Nov 9, 2014

It would be very useful to be able to specify the maximum number of objects to return in a query, similar to LIMIT in SQL. Otherwise the RealmResults list must be manually trimmed with subList.

@cmelchior

This comment has been minimized.

Contributor

cmelchior commented Nov 9, 2014

Hi Greg

Thank you for the feedback.

RealmResults are lazy loaded, so they don't take up additional memory whether you have 100 or 1.000.000 results.

Also the design intent was for RealmLists to behave like standard arrays, which means that subList() is the right way to do it.

However you are not the first to ask for a limit functionality, so either we have to be better about communicating the right use pattern or perhaps add limit as a shorthand for subList() like you suggested.

@cmelchior

This comment has been minimized.

Contributor

cmelchior commented Nov 9, 2014

To clarify a little. While the results are lazy loaded in Android our Realm core does maintain a list of the results. However it is done in such a way that it is really lightweight and compact.

@gjcameron

This comment has been minimized.

gjcameron commented Nov 9, 2014

Thanks. Using subList works fine for me in most circumstances, the particular use case where I think it would be useful to be able to specify a limit in the query is when using an autoupdating RealBaseAdapter.

Perhaps this wasn't the intended use for the RealmBaseAdapter, but being able to specify a robust query for results (including sort order, as mention in my other enhancement request) that autoupdates would be very powerful.

@cmelchior cmelchior added the P1 label Apr 15, 2015

@cmelchior cmelchior changed the title from No way to limit the number of objects retrieved in a query to LIMIT Apr 15, 2015

@cmelchior cmelchior added the Blocked label Apr 16, 2015

@cmelchior cmelchior added P2 and removed P1 labels Apr 23, 2015

@bmunkholm bmunkholm added T:Feature and removed T:Enhancement labels Jun 13, 2015

@haskellcamargo

This comment has been minimized.

haskellcamargo commented Jan 21, 2016

+1. Although the results are lazily loaded, subList is unsafe (IllegalArgumentException, IndexOutOfBoundsException) and specifying a value out of range will give a runtime error. This is particularly problematic when you deal with pagination, for example, If I want to take the values in a range of 100 starting by page 1:

List<Equipment> filtered;
try {
  filtered = results.subList((page - 1) * 100, page * 100);
 } catch (IndexOutOfBoundsException lastPage) {
  try {
    filtered = results.subList((page - 1) * 100, results.size());
  } catch (IllegalArgumentException noMoreData) {
    filtered = new ArrayList<>();
  }
}
@saket

This comment has been minimized.

saket commented Jan 21, 2016

@haskellcamargo Isn't it the dev's job to check the size before calling subList? I maintain a utility method subListSafely which does exactly this. This isn't the job of Realm IMO. :)

@haskellcamargo

This comment has been minimized.

haskellcamargo commented Jan 21, 2016

Not exactly in this case. In case of LIMIT or TOP, we would securely have the values (also if we provided TOP 100 when we have only 50 items, and we lose the query abstraction that is provided by Realm. It is made to leave the boilerplate away. We lose an utility that is safely implemented by the relational databases and that is quite common. We mix the index check logic with the query logic (ah, and don't forget we have no extension methods in Java, like C#, to abstract it in a respectable way by extending RealmResult). I really believe that, as I said, although it is lazy, it would be useful to have a built-in feature for that and to keep the things clear. Abstraction and expressiveness are the way.

@cmelchior

This comment has been minimized.

Contributor

cmelchior commented Jan 21, 2016

You would also have safety using Math.min/max:

int size = results.size();
results.subList(Math.max((page - 1) * 100, 0) , Math.min(page * 100, size));

That said we are not against adding some kind of LIMIT functionality as it can also have a positive impact on performance alongside the other benefits you mentioned. It does not have a high priority however, so I cannot give you any timeline for when we can add it.

@AlokBansal8

This comment has been minimized.

AlokBansal8 commented Feb 15, 2016

👍

3 similar comments
@bleppard

This comment has been minimized.

bleppard commented Mar 25, 2016

👍

@mmublackpirate

This comment has been minimized.

mmublackpirate commented Apr 6, 2016

👍

@olidroide

This comment has been minimized.

olidroide commented May 1, 2016

👍

@xiaolongyuan

This comment has been minimized.

xiaolongyuan commented May 24, 2016

+1

3 similar comments
@davroux

This comment has been minimized.

davroux commented May 27, 2016

👍

@frogggias

This comment has been minimized.

frogggias commented Jul 29, 2016

👍

@carloseduardosx

This comment has been minimized.

carloseduardosx commented Sep 19, 2016

👍

@Zhuinden

This comment has been minimized.

Contributor

Zhuinden commented Sep 19, 2016

@carloseduardosx I don't understand why you guys want a LIMIT.

All you need to do is SORT your RealmResults, and then do not index above your arbitrary threshold.

For example, in a Results that "contains" 225 elements, to obtain the second page (1 -> 2) of 50, all you need to do is index like this

// pageNum is 2
int min = (pageNum-1)*50;   //50
int max = pageNum*50;   //100, not inclusive
int size = realmResults.size(); // 225

// pageNum is 5
int min = (pageNum-1)*50;   //200
int max = pageNum*50;   //250, not inclusive
int size = realmResults.size(); // 225

Adapter:

public int getItemCount() {
    // assume pageNum = 5
    int min = (pageNum-1)*50;   //200
    int max = pageNum*50;   //250, not inclusive
    int size = realmResults.size(); // 225
    int elementCount = Math.min(max-min, size-min);
    return elementCount < 0 ? 0 : elementCount;
}

Then index

public void onBindViewHolder(RecyclerView.Holder holder, int position) {
     Element element = getItem(pageCount * 50 + position);
}

I did not test this but conceptually this is equivalent to a "LIMIT" as a query in terms of functionality in your application.

There is no point to limiting a Results. Just paginate your elements.

You guys don't even need subList. I don't understand why you are making your lives harder.

@Zhuinden

This comment has been minimized.

Contributor

Zhuinden commented Sep 19, 2016

Although I guess I can see a .skip(20).take(50) instead of limit().

@ahmadalibaloch

This comment has been minimized.

ahmadalibaloch commented Sep 25, 2016

@Zhuinden And we don't understand why you guys dont implement the Limit query method to satisfy hundred people ;-). I need to use RealmResults for RecycleView (autoupdating) and need to limit results in a products suggestion page. I have spent 30 minutes exploring best way and then implementing custom way. its a basic feature in Library like Realm.
This is how I am doing:

RealmResults<Bayan> bayans = realm.where(Bayan.class).findAll();
List<String> bayanIds = Stream.of(bayans).limit(10).map(x -> x.Id).collect(Collectors.toList());
return realm.where(Bayan.class).in(BayanFields.ID, bayanIds.toArray(new String[])).findAll();
@Zhuinden

This comment has been minimized.

Contributor

Zhuinden commented Sep 25, 2016

@ahmadalibaloch hey, I'm just a community member, not an official realm person 👅

But to paginate the results, you just have to limit your index to show from the lowest and highest bound of your index, and show item size of the minimum of 30 or the remaining element count

I'd assume the reason why this is not trivial is because of minDate and the other additional methods of a result set that don't know how to evaluate themselves for a subset of the results

@beeender

This comment has been minimized.

Contributor

beeender commented Dec 27, 2016

Another use case is to delete first n objects from a query results.
See http://stackoverflow.com/questions/41327579/how-to-delete-first-n-rows-in-realm

@cmelchior

This comment has been minimized.

Contributor

cmelchior commented Jan 30, 2017

Core issue tracking this: realm/realm-core#1239

@dtmandroid

This comment has been minimized.

dtmandroid commented Apr 4, 2017

I have a Record Table. I want to display 5 records every time, user clicks on Next button until last record of Table. Please help me.. Thank you for your time...

@beeender

This comment has been minimized.

Contributor

beeender commented Apr 4, 2017

@dtmandroid it is actually very simple, you could do something in your adapter:

public class MyAdapter {
private int baseIndex;

public void selectPage(int page) {
    baseIndex = 5 * page;
}

@Override
public void getIndex(int pos) {
    return adapterData.get(baseIndex + pos);
}

@Override
public void getCount() {
    return adapterData.size() - 5 > 0 ? 5 : adapterData.size() - baseIndex;
}

}

The above just shows the basic idea how to achieve you use case, I am sure you need to write more code to make a full implementation.

@dtmandroid

This comment has been minimized.

dtmandroid commented Apr 4, 2017

@beeender Thank for the answer. I could get first 5 records but crashes when get next 5 records. So will you please explain where to write selectPage() and getIndex() method and use of it.. Thank You,

@Zhuinden

This comment has been minimized.

Contributor

Zhuinden commented Apr 4, 2017

@dtmandroid you can also try this approach http://stackoverflow.com/a/38873498/2413303

@bmunkholm bmunkholm added S:Backlog and removed S:P2 Backlog labels May 18, 2017

@bmunkholm bmunkholm removed the S:Backlog label Aug 8, 2017

@null-dev

This comment has been minimized.

null-dev commented Apr 1, 2018

Please please please implement this. Calling size on RealmResults with > 20000 items can take 5+ seconds to complete. Lazy loading doesn't help so much when I don't know what is available to load!

@bmunkholm bmunkholm added the O:User label May 30, 2018

@babedev

This comment has been minimized.

babedev commented Jul 10, 2018

I also have problem with count() or `size. I have data over than 300K row it took about 3 seconds to finished counting.

Here is my code

realm.where(SomeClass::class.java)
  .findAll()
  .asFlowable()
  .map { it.count() }

I use findAll() with Flowable because I want to observe event on this table.

@Zhuinden

This comment has been minimized.

Contributor

Zhuinden commented Jul 10, 2018

You might want to try realm.where<SomeClass>().findAllAsync().asFlowable().filter { it.isLoaded() }

@cmelchior cmelchior referenced this issue Aug 24, 2018

Merged

Support LIMIT #6126

9 of 9 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment