Skip to content
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
Closed

LIMIT #544

gjcameron opened this issue Nov 9, 2014 · 28 comments
Labels
Blocked This issue is blocked by another issue Design-Required O-Community T-Feature

Comments

@gjcameron
Copy link

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Author

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 No way to limit the number of objects retrieved in a query LIMIT Apr 15, 2015
@cmelchior cmelchior added the Blocked This issue is blocked by another issue label Apr 16, 2015
@cmelchior cmelchior added P2 and removed P1 labels Apr 23, 2015
@haskellcamargo
Copy link

+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
Copy link

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
Copy link

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
Copy link
Contributor

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
Copy link

👍

3 similar comments
@jade-42
Copy link

jade-42 commented Mar 25, 2016

👍

@yemyatthu1990
Copy link

👍

@olidroide
Copy link

👍

@xiaolongyuan
Copy link

+1

3 similar comments
@davroux
Copy link

davroux commented May 27, 2016

👍

@frogggias
Copy link

👍

@carloseduardosx
Copy link

👍

@Zhuinden
Copy link
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
Copy link
Contributor

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

@ahmadalibaloch
Copy link

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
Copy link
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
Copy link
Contributor

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
Copy link
Contributor

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

@dtmandroid
Copy link

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
Copy link
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
Copy link

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
Copy link
Contributor

Zhuinden commented Apr 4, 2017

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

@null-dev
Copy link

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!

@babedev
Copy link

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
Copy link
Contributor

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

@cmelchior cmelchior mentioned this issue Aug 24, 2018
9 tasks
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Blocked This issue is blocked by another issue Design-Required O-Community T-Feature
Projects
None yet
Development

No branches or pull requests