I am using realm database for my android app. I wanna know how to use a query called "between" for a string. For example
final RealmResults<PersonModel> list = myRealm.
where(PersonModel.class).between("name","A","E").findAll();
its not working for the string which i have used.But its working only for int types. Can someone please help me.
final RealmResults<PersonModel> list = myRealm
.where(PersonModel.class)
.beginsWith("name","A")
.or().beginsWith("name","B")
.or().beginsWith("name","C")
.or().beginsWith("name","D")
.or().beginsWith("name","E")
.findAllSorted("name", Sort.ASCENDING);
According to https://realm.io/docs/java/latest/api/io/realm/RealmQuery.html query does not have method between accepting strings as parameters. Between usually can be replaced with pair of less-than and greater-than operators, but those does not support strings as well. So if you want to do between for strings lexicographically, the only way is to exclude between at all and do filtering in java.
Example:
final RealmResults<PersonModel> list = Realm.getDefaultInstance().where(PersonModel.class).findAll();
Collection<PersonModel> betweenModels = new ArrayList<>();
for (PersonModel m : list) {
if(m.getName().compareTo("A") >= 0 && m.getName().compareTo("E") <= 0) {
betweenModels.add(m);
}
}
betweenModels will contain items with names bigger-equal than "A" and less-equal than "E" lexicographically
Related
How to get multiple documents from a Collection in firebase if we want to filter using not_in operator with a uniqueId list of documents.
I have a arrayList like this:
ArrayList<String> idList = new ArrayList();
idList.addAll(uniqueIdList);
// now idList have more than 500 uniqueId
Query query = db.collection("my_collection")
.whereEqualTo("status", "DONE")
.whereNotIn("uniqueId", idList)
.orderBy("uniqueId", Query.Direction.DESCENDING)
.orderBy("createdOn", Query.Direction.DESCENDING);
/* FIREBASE DOCUMENTATION SAYS
------------------------------
Use the in operator to combine up to 10 equality (==)
clauses on the same field with a logical OR */
If the idList object have more than 10 items. It crashes the android application due to FirestoreException.
So, should we not use where_not_in operator? But I have specific demand of this for the query.
So, if you want to query using where_not_in operator in Firebase then, you have to do some part from client side also. The query has a serious limitation. So here is a solution.
// Assume idList contains the uniqueId of documents that you don't want
// Assume status can be DONE or PENDING
// Assume list_objects is the ArrayList you have to pass to Recycler view or list view in your app
if (idList.size() > 0 && idList.size() <= 10) {
query = db.collection("my_collection")
.whereEqualTo("status", "DONE")
.whereNotIn("uniqueId", idList)
.orderBy("uniqueId", Query.Direction.DESCENDING)
.orderBy("createdOn", Query.Direction.DESCENDING);
// your on success code here
} else {
query = db.collection("my_collection")
.whereEqualTo("status", "DONE")
.orderBy("createdOn", Query.Direction.DESCENDING);
// here we are fetching all data where status is done
query.get().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
List<Object> list_toRemove = new ArrayList<>();
list_objects = task.getResult().toObjects(ClassName.class);
for (int i = 0; i < list_objects.size(); i++) {
Object item = list_objects.get(i);
if (idList.contains(item.getUniqueId())) {
list_toRemove.add(list_objects.get(i));
}
}
list_objects.removeAll(list_toRemove);
}
}
// remove the data manually here and we are now good. There is no other way for now.
}
So this is a limitation in firebase, but if we look at the advantages of using firebase firestore DB then it's a trade off.
The rule is that if you cannot filter data using query then fetch with applying filters that are possible then again filter using the Collection Framework (if you are using Java). All things are possible in this DB.
I'm trying to list documents that matches field String value from ArrayList.
Simply:
I have ArrayList with tags stored at runtime
and documents with field tag
and I want to query documents that matches tag with one of tags stored in ArrayList. Is this possible with official query or does I have to download all documents and filter it client-side? Thanks for any answers.
Also, this is my method generating query:
public static Query getQueryForFollowed(DocumentSnapshot snapshots) {
if (snapshots == null || !snapshots.exists()) {
return FirebaseFirestore.getInstance().collection("posts").whereEqualTo("null", "null"); // return query that will get nothing
}
ArrayList<String> f = processFollowedTags(snapshots);
Query query = FirebaseFirestore.getInstance()
.collection("posts")
.whereEqualTo("tag", f.get(0));
for (int i = 1; i < f.size(); i++) {
query = query.whereEqualTo("tag", f.get(i));
}
return query;
}
I have debugged code and query has contained requested conditions, but query didn't found any document matching it.
Try This
Query query = FirebaseFirestore.getInstance()
.collection("posts")
.whereEqualTo("tag", f.get(0)).orderBy("tag", Query.Direction.ASCENDING);;
After some more search on Google I have found that querying field to multiple values is not available.
According to:
https://stackoverflow.com/a/46633294/8428193
https://github.com/firebase/firebase-js-sdk/issues/321
Below code snippet may help you.
fun arrayContainsQueries() {
// [START array_contains_filter]
val citiesRef = db.collection("cities")
citiesRef.whereArrayContains("regions", "west_coast")
// [END array_contains_filter]
}
ref : git
As of Nov 2019 this is now possible to do with the in query.
With the in query, you can query a specific field for multiple values
(up to 10) in a single query. You do this by passing a list containing
all the values you want to search for, and Cloud Firestore will match
any document whose field equals one of those values.
it would look like this:
Query query = FirebaseFirestore.getInstance()
.collection("posts")
.whereIn("tag", f);
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.
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();
Now realm v 1.2.0 support RealmQuery.in() for a comparison against multiple values.
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();
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
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();
I have a List<String> ids and I want all the FooRealmObjects that have the ID field included in the ids list.
I could iterate through the ids list and query objects by ID, but I was hoping there is a one-liner for this, like :
realm.where(Foo.class).in("id", ids).findAll();
Any ideas?
Now realm already support the feature you want.
Added in Realm Java 1.2.0. (https://github.com/realm/realm-java/issues/841)
Now you can do exactly what you want:
realm.where(Foo.class).in("id", ids).findAll();
As Jeremy mentioned, querying with a list of parameters is not possible (for now), but his answer does not work at all.
This is the workaround I used:
List<String> ids = ...;
Realm realm = Realm.getInstance(mContext);
RealmQuery<Foo> query = realm.where(Foo.class);
for (int i = 0; i < ids.size() - 1; i++) {
query = query.equalTo("id", ids.get(i)).or();
}
query = query.equalTo("id", ids.get(ids.size() - 1));
RealmResults<Foo> foos = query.findAll();
I don't believe there is a method according to the documentation to query like this. You could do something like the following:
RealmQuery query = realm.where(Foo.class);
for (String id : ids) {
query.equalTo("id", id).or();
}
query.findAll();
Might have to iterate through it using ;;; to remove the last .or() but I'm not sure.
I currently have a statement which reads
if(Arrays.asList(results).contains("Word"));
and I want to add at least several more terms to the .contains parameter however I am under the impression that it is bad programming practice to have a large number of terms on one line..
My question is, is there a more suitable way to store all the values I want to have in the .contains parameters?
Thanks
You can use intersection of two lists:
String[] terms = {"Word", "Foo", "Bar"};
List<String> resultList = Arrays.asList(results);
resultList.retainAll(Arrays.asList(terms))
if(resultList.size() > 0)
{
/// Do something
}
To improve performance though, it's better to use the intersection of two HashSets:
String[] terms = {"Word", "Foo", "Bar"};
Set<String> termSet = new HashSet<String>(Arrays.asList(terms));
Set<String> resultsSet = new HashSet<String>(Arrays.asList(results));
resultsSet.retainAll(termSet);
if(resultsSet.size() > 0)
{
/// Do something
}
As a side note, the above code checks whether ANY of the terms appear in results. To check that ALL the terms appear in results, you simply make sure the intersection is the same size as your term list:
resultsSet.retainAll(termSet);
if(resultSet.size() == termSet.size())
You can utilize Android's java.util.Collections
class to help you with this. In particular, disjoint will be useful:
Returns whether the specified collections have no elements in common.
Here's a code sample that should get you started.
In your Activity or wherever you are checking to see if your results contain a word that you are looking for:
String[] results = {"dog", "cat"};
String[] wordsWeAreLookingFor = {"foo", "dog"};
boolean foundWordInResults = this.checkIfArrayContainsAnyStringsInAnotherArray(results, wordsWeAreLookingFor);
Log.d("MyActivity", "foundWordInResults:" + foundWordInResults);
Also in your the same class, or perhaps a utility class:
private boolean checkIfArrayContainsAnyStringsInAnotherArray(String[] results, String[] wordsWeAreLookingFor) {
List<String> resultsList = Arrays.asList(results);
List<String> wordsWeAreLookingForList = Arrays.asList(wordsWeAreLookingFor);
return !Collections.disjoint(resultsList, wordsWeAreLookingForList);
}
Note that this particular code sample will have contain true in foundWordInResults since "dog" is in both results and wordsWeAreLookingFor.
Why don't you just store your results in a HashSet? With a HashSet, you can benefit from hashing of the keys, and it will make your assertion much faster.
Arrays.asList(results).contains("Word") creates a temporary List object each time just to do linear search, it is not efficient use of memory and it's slow.
There's HashSet.containsAll(Collection collection) method you can use to do what you want, but again, it's not efficient use of memory if you want to create a temporary List of the parameters just to do an assertion.
I suggest the following:
HashSet hashSet = ....
public assertSomething(String[] params) {
for(String s : params) {
if(hashSet.contains(s)) {
// do something
break;
}
}
}