I'm using SugarORM for my Android app. I want to load messages from the SQLite DB but need an offset.
So I load message 5-15 like for pagination.
Unfortunately the offset function doesn't seem to work as expected.
I wrote:
query = Select.from(Message.class)
.where(Condition.prop("MESSAGES").eq(Long.toString(getId())))
.orderBy("timestamp DESC")
.limit("5")
.offset("10");
query.list();
But this only gives me the limit of 5 elements but doesn't use any offset.
Same if I parameterize the query call like this:
List<Message> messages = getAllMessagesQuery.offset("5").list();
Offset isn't working.
Am I doing something wrong? I use the current SugarORM version 1.5
( compile 'com.github.satyan:sugar:1.5')
stating the working offset functionality. So this shouldn't be the issue.
Any ideas how to make this work?
Well, not sure this is the best way to do but at least it's working this way.
If I add the short version to the limit things work fine.
So using the query like this:
List<Message> messages = getAllMessagesQuery.limit("5,10").list();
gives me 10 messages with a 5 message offset.
If that is too dirty, a raw query is also working fine. So you write:
List<Message> messages = Chat.findWithQuery(Message.class, "Select * from Message where Chat = ? ORDER BY timestamp DESC LIMIT 10 OFFSET 5", getId().toString());
Still no idea how to use the offset parameter directly but at least it works this way.
Related
In my Android app we use couchbase lite database version 2.8.6
I run three database queries.
One item in where clause.
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE)))
In the result I see three items from database printed to a console. As expected. Format here ans below is id|timestamp|rating
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
e02d0eb3-6c9b-4942-b43c-a752eefc77a8|1630525956184|2147483647
I add and() condition to where() to get all items where type = 'type' AND rating < 1
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE))
.and(Expression.property("rating").lessThan(Expression.intValue(1))
)
Result is as expected as we search everything with rating < 1, third item is filtered out.
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
Finally, I want to see records where type = 'type' AND rating < 1 AND timestamp <= 1
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE))
.and(Expression.property("rating").lessThan(Expression.intValue(1))
.and(Expression.property("timestamp")).lessThanOrEqualTo (Expression.longValue(1))
)
)
And now the result is really strange as I receive three items form the database. And the third one has timestamp much greater than 1 put into the query.
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
e02d0eb3-6c9b-4942-b43c-a752eefc77a8|1630525956184|2147483647
Any ideas how to make it work with multiple and()? If I try to remove the second and() and keep the third one everything works as expected.
After deep investigations I found several problems in my code:
.and() should be called at the end of the "child" condition and not at the "parent" level.
For the conditions like this
val condition1 = Expression.property("type").equalTo(Expression.string(DOC_TYPE))
val condition2 = Expression.property("rating").lessThan(Expression.intValue(1))
val condition3 = Expression.property("timestamp")).lessThanOrEqualTo (Expression.longValue(1))
The correct way is
.where(condition1.and(
condition2.and(
condition3.and(
...
)
)
)
but NOT like I've tried
.where(condition1.and(condition2)
.and(condition3)
.and(...)
)
For the creation of the object I used a code that converts an object to Map<String, Any> before saving to couchbase. Everything seemed to be OK till I realized that Long was converted to Double.
The last point, I have much complicated queries and inside one of them I accidentally used .add() instead of .and(). No comments.
Hope this will help to somebody to save some time.
I would expect that the query would be as you did originally:
.where(condition1.and(condition2)
.and(condition3)
.and(...))
I think there is an additional parenthesis here that seems to be wrong:
.and(Expression.property("timestamp"))
I have one Android project where I need to query nearby items & these items should be sorted by time.
Basically, I need docs that are in 100KM. Sorted by time (Field).
So I have checked Firestore docs for this & I got solution (Add geoHash to docs & then query them by geoHasBounds) But there is an issue what if there are 1k docs in 100km then it will load all which is not good, so how can I limit those different queries & gets only 25-30 docs then next 25-30 docs ??
In short, this is what I need-
How can I query the latest 25 docs in 100KM radius & when the user scroll down the next 25 docs?
this is my code of query-
List<GeoQueryBounds> bounds = GeoFireUtils.getGeoHashQueryBounds(center, radiusInM);
final List<Task<QuerySnapshot>> tasks = new ArrayList<>();
for (GeoQueryBounds b : bounds) {
Query newQuery = itemQuery.orderBy("geoHash").startAt(b.startHash).endAt(b.endHash);
tasks.add(newQuery.get());
}
// Collect all the query results together into a single list
Tasks.whenAllComplete(tasks).........
What you are looking for is called pagination. I have answered a question here on Stackoverflow, where I have explained a recommended way in which you can paginate queries by combining query cursors with the "limit() method". I also recommend you take a look at this video for a better understanding.
If you are willing to try Paging 3 library, please see below an article that will help you achieve that.
How to paginate Firestore using Paging 3 on Android?
Edit:
The Tasks.whenAllComplete() method:
Returns a Task with a list of Tasks that completes successfully when all of the specified Tasks complete.
So you can then simply convert each object to a type of object that you need and paginate that list accordingly. Unfortunately, this implies getting all the objects in the first place. Otherwise, you can divide those queries into separate queries and treat them accordingly, by using separate paginantion.
I just start using Firebase in Android and I wrote query like this.
messageSearchQuery = FirebaseDatabase.getInstance().getReference().child("Message")
.child(conversationID).limitToLast(INITIAL_MESSAGE_COUNT)
.orderByChild("timestamp").startAt(participant.joiningDate).endAt(endAt);
I can only give limitToFirst, limitToLast, startAt, endAt. (I think there is no center)
I need to give timestamp (e.g 10 am sharp) and i wanna query 10 message before 10 am and 10 message after 10 am. (but i don't know when it start, when it end).
Edit
What I want to do is something like this.
messageSearchQuery = FirebaseDatabase.getInstance().getReference().child("Message").
child(conversationID).
orderByChild("timestamp").equalTo(endAt).limitToFirst(INITIAL_MESSAGE_COUNT).limitToLast(INITIAL_MESSAGE_COUNT);
But if I do, it crash like this.
java.lang.IllegalArgumentException: Can't call limitToLast on query with previously set limit!
How shall I do?
My data in firebase is something like this.
You can select a range by combining startAt and endAt, both of which operate on the child you order on. For example if you want messages between 10am and 10pm on a certain date, you'd do:
long timestampOf10am = ...;
long timestampOf10pm = ...;
messageSearchQuery = FirebaseDatabase.getInstance().getReference().child("Message")
.child(conversationID)
.orderByChild("timestamp").startAt(timestampOf10am).endAt(timestampOf10pm)
.limitToLast(INITIAL_MESSAGE_COUNT);
Update: If you need 10 items before 10am and 10 items after 10am, you'll need to fire two queries and merge the results client-side.
long timestampOf10am = ...;
beforeMessageSearchQuery = FirebaseDatabase.getInstance().getReference().child("Message")
.child(conversationID)
.orderByChild("timestamp").startAt(timestampOf10am)
.limitToFirst(INITIAL_MESSAGE_COUNT);
afterMessageSearchQuery = FirebaseDatabase.getInstance().getReference().child("Message")
.child(conversationID)
.orderByChild("timestamp").endAt(timestampOf10am)
.limitToLast(INITIAL_MESSAGE_COUNT);
I'm working with an Android App that functions as an instant messaging service, and I'm at the point of pulling the message data through into a RecyclerView. I have my Firebase Query object returning all the messages that match the id of the chat that has been loaded, this is done like so:
Query qChatMessages = mDbRefMessages
.orderByChild("messageChat")
.equalTo(mChatId);
So far so good, and this is returning the collection of messages that I expect. The problem is now that, upon passing them to the RecyclerView to be displayed, they come out in the inverse order of how you would typically expect an instant messenger to display, so the messages are actually getting older as you scroll down the chat.
My message nodes in the database all have a messageTimestamp field associated with them, so this is what I would want to sort the data by. The problem is that I don't seem to be able to find a way of ordering the data by any field other than the one that I'm querying on, or getting the results back from Firebase and subsequently ordering them.
Does anyone know how I can work around this, or if there's some Firebase capabilities I'm not aware of?
Thanks in advance,
Mark
The easiest way is to store an extra piece of data in your message nodes which is the epoch time multiplied by -1: this way you can sort on this field and the query will return the right order.
See this post on how to get the epoch time: how to get the number of seconds passed since 1970 for a date value?
However, note that with your current data structure, you will encounter a problem: you will need to sort on this new data (e.g. with .orderByChild("messageCreationTime")) AND filter for a given mChatId (e.g. with equalTo(mChatId)), which is not possible.
So, you would have to re-structure your database (if this is possible) like this:
- messages
- mChatId
- messageUniqueID <- most probably auto-generated by Firebase
- messageTitle: ....
- messageCreationTime: -1525857044
And you would query by:
Query qChatMessages = databaseReference.child("messages").child(mChatId)
.orderByChild("messageCreationTime");
I have a query that works fine in an Azure SQL database, but I'm trying to use it within my Android application and I can't get it to work correctly. It is to find any overlaps in time for bookings. Here is the SQL query with some dummy data, arrival and depart are both integers:
Select * from bourguestMob.tableObjectBookings
where tabObjID = 28
and day = 30
and month = 3
and year = 2015
and ((arrival <= 1600 and depart > 1600)
or (arrival< 1800 and depart >= 1800));
Using the Mobile Service provided, I have to use the query as something like:
tableObjectBookingsTable.where().field("tabObjID").eq(tables.get(i).getId())
.and().field("day").eq(day).and().field("month").eq(month).and().field("year").eq(year)
.and().field("arrival").lt(intTime).or().field("arrival").eq(intTime).and().field("depart").gt(intTime)
That's what I have partially but I think some part of the query needs to be nested to be evaluated correctly.
I think what you want is to change the end of your query to look like so:
.and(field("arrival").lt(intTime).or()
.field("arrival").eq(intTime).and().field("depart").gt(intTime))
It helps me to look at the oData string to check if you get it right, take a look here for some samples of complex queries:
https://github.com/Azure/azure-mobile-services/blob/master/sdk/android/test/sdk.testapp.tests/src/com/microsoft/windowsazure/mobileservices/sdk/testapp/test/MobileServiceQueryTests.java#L724