Reputation: 504
I have a Rating Realm objects list as Follows:
public class RatingRealmObject extends RealmObject {
@SerializedName("average")
private float average;
@SerializedName("raters")
private int raters;
public float getAverage() {
return average;
}
public void setAverage(float average) {
this.average = average;
}
public int getRaters() {
return raters;
}
public void setRaters(int raters) {
this.raters = raters;
}
}
I want to sort the RealmResultList by descending order of average but the number of raters should be greater than or equal to 5.
e.g. If we have two recipes as A and B.
A has average rating 4, and no. of raters are 8 and,
B has average rating 5 and no. of raters are 4
then after sort, A should come first in the list.
Any help how to make the condition in realm query.
Upvotes: 0
Views: 1764
Reputation: 504
@EpicPandaForce and @beeender Thank you guys, You both helped me alot to solve this problem.
As I am using GSON library for the deserialization so as per GSON guidelines setter method does not call. So additional field computation in Rating object didn't work for me.
I have solved my problem by the first solution provided by @EpicPandaForce.
List<RecipeRealmObject> ratingMoreThan5List = recipeRealmResult.where().greaterThanOrEqualTo("rating.raters", 5).findAllSorted("rating.average", Sort.DESCENDING);
List<RecipeRealmObject> ratingLessThan5List = recipeRealmResult.where().lessThan("rating.raters", 5).findAllSorted("rating.average", Sort.DESCENDING);
List<RecipeRealmObject> ratingNullList = recipeRealmResult.where().isNull("rating").findAll();
List<RecipeRealmObject> recipeList = new ArrayList<>();
recipeList.addAll(ratingMoreThan5List);
recipeList.addAll(ratingLessThan5List);
recipeList.addAll(ratingNullList);
onCompleteListener.onSearchComplete(recipeList);
Upvotes: 0
Reputation: 3565
You could define a weight
field in your RatingRealmObject
, and compute the weight
whenever you set average
or raters
. Then the solution will be just as simple as sorting by the weight
.
Some example:
public class RatingRealmObject extends RealmObject {
private float average;
private int raters;
@Index
private float weight;
private void computeWeight() {
// This is for showing the idea, you need to change how to calculate the weight depends on your requirement.
weight = raters / 5 + average;
}
public float getAverage() {
return average;
}
public void setAverage(float average) {
this.average = average;
computeWeight();
}
public int getRaters() {
return raters;
}
public void setRaters(int raters) {
this.raters = raters;
computeWeight();
}
}
Then you could just have realm.where(RatingRealmObject.class).findAllSortedAsync("weight");
Upvotes: 1
Reputation: 81549
One possible solution would be to concatenate two RealmResults together to get the sort you want, see here.
Another solution would be that if you extend your schema with an additional field
public class RatingRealmObject extends RealmObject {
@Inedx
private float average;
private int raters;
@Index
private int hasOverFiveRaters; // 0 or 1 like a TINYINT in SQLite
public float getAverage() {
return average;
}
public void setAverage(float average) {
this.average = average;
}
public int getRaters() {
return raters;
}
public void setRaters(int raters) {
this.raters = raters;
this.hasOverFiveRaters = raters >= 5 ? 1 : 0;
}
}
Because now you can do
realm.where(RatingRealmObject.class)
.findAllSortedAsync(
new String[] {"hasOverFiveRaters", "average"},
new Sort[] { Sort.DESCENDING, Sort.DESCENDING });
P.S.: realm.copyFromRealm()
copies every single element from the Realm (in your case, on the UI thread) and therefore removes lazy evaluation, it is generally not needed nor recommended unless you are trying to create a detached modifiable object or want to send the RealmObject through GSON.
Upvotes: 3