Objectify Ref.get() called twice - objectify

If I call Ref<>.get() second time, does it query datastore or uses the already loaded value?

It only goes to the datastore (or memcache, or whatever) once. The value is cached in the Ref itself.

Related

Is there a way to retrieve realtime firebase map as a linkedhashmap or at least maintain the order it is saved in

I have a map of string boolean pairs saved on firebase realtime database and was wondering if there is a way to retrieve it in kotlin as a linkedhashmap such that the original order remains in place.
I have tried typecasting to a linkedhashmap and got an error that hashmap cannot be typecasted to linked hashmap, I then tried calling the linkedhashmap constructor method with the parameter being the data from the database as a hashmap but that does not maintain the order
Properties in JSON are by definition not in any specific order.
While you can retrieve data from Firebase in a specific order, by calling one of its orderBy... operations, that order will be lost when you call .value in the DataSnapshot as DataSnapshot.value returns a Map, which is unordered again.
If you want to retrieve the nodes in a specific order:
Call orderBy... to get the nodes in a specific order.
Loop over the children of the snapshot you get back to process them in order, and only call value on each specific child node.

Can we trigger firebase cloud functions when we create a collection (not "document")?

I am trying to achieve a scenario where firebase triggers only once when a collection is created and not every time that a document is added to the collection. Let's say I want it to trigger only for the first document added to the collection and not for every other document added to the same collection. How can that be done? Please help !!!
There is no such trigger for Cloud Functions. Your trigger path must specify exactly one document, or use wildcards to specify a path that could possibly match many documents.
If you want to know what a collection contains its first document, you will have to either:
Maintain a count of documents in that collection (perhaps in yet another document in another collection), and trigger of the change of that value when it goes from 0 to 1.
Query all of the documents in the collection where a document was just created in order to figure out if it was the first one.
Both of these requires a fair amount of extra code - very much not trivial to implement correctly for arbitrary collections. They could also run into problems under heavy load. If these options won't work for you, I suggest figuring out another way to get you function to trigger at the right time.
While It's not possible to do directly. You can check if collection contains any elements, and if it does it means that it exists.
const result =await firestore.collection("collection").limit(1).get()
if(result.size){
// Collection exists
}

Optimizing the number of reads from firestore server using caching or snapshot listener

I am rendering the following view using Firebase. So basically the search is powered by a Firebase query.
I am using the following code:
Query query = FirebaseUtils.buildQuery(
fireStore, 'customers', filters, lastDocument, documentLimit);
print("query =" + query.toString());
QuerySnapshot querySnapshot = await query.getDocuments();
print("Got reply from firestore. No of items =" + querySnapshot.documents.length.toString());
Questions:
If the user hits the same query, again and again, it still hits the server. I checked this by using doc.metadata.isFromCache and it always returns false.
Will using query snapshots help in reduce no of reads for this search query? I guess no. As the user is changing the query again and again.
Any other way to limit the number of reads?
If the user hits the same query, again and again, it still hits the server. I checked this by using doc.metadata.isFromCache and it always returns false.
If you are online, it will always return false and that's the expected behavior since the listener is always looking for changes on the server. If you want to force the retrieval of the data from the cache while you are online, then you should explicitly specify this to Firestore by adding Source.CACHE to your get() call. If you're offline, it will always return true.
Will using query snapshots help in reduce no of reads for this search query? I guess no. As the user is changing the query again and again.
No, it won't. What does a query snapshot represent? It's basically an object that contains the results of your query. However, if you perform a query, "again and again", as long as it's the same query and nothing has changed on the server, then you will not be charged with any read operations. This is happening because the second time you perform the query, the results are coming from the cache. If you perform each time a new search, you'll always be billed with a number of read operations that are equal with the number of elements that are returned by your query. Furthermore, if you create new searches and the elements that are returned are already in your cache, then you'll be billed with a read operation only for the new ones.
Any other way to limit the number of reads?
The simplest method to limit the results of a query is to use a limit() call and pass as an argument the number of elements you want your query to return:
limit(10)

How can I query for all new and updated documents since last query?

I need to query a collection and return all documents that are new or updated since the last query. The collection is partitioned by userId. I am looking for a value that I can use (or create and use) that would help facilitate this query. I considered using _ts:
SELECT * FROM collection WHERE userId=[some-user-id] AND _ts > [some-value]
The problem with _ts is that it is not granular enough and the query could miss updates made in the same second by another client.
In SQL Server I could accomplish this using an IDENTITY column in another table. Let's call the table version. In a transaction I would create a new row in the version table, do the updates to the other table (including updating the version column with the new value. To query for new and updated rows I would use a query like this:
SELECT * FROM table WHERE userId=[some-user-id] and version > [some-value]
How could I do something like this in Cosmos DB? The Change Feed seems like the right option, but without the ability to query the Change Feed, I'm not sure how I would go about this.
In case it matters, the (web/mobile) clients connect to data in Cosmos DB via a web api. I have control of the entire stack - from client to back-end.
As the statements in this link:
Today, you see all operations in the change feed. The functionality
where you can control change feed, for specific operations such as
updates only and not inserts is not yet available. You can add a “soft
marker” on the item for updates and filter based on that when
processing items in the change feed. Currently change feed doesn’t log
deletes. Similar to the previous example, you can add a soft marker on
the items that are being deleted, for example, you can add an
attribute in the item called "deleted" and set it to "true" and set a
TTL on the item, so that it can be automatically deleted. You can read
the change feed for historic items, for example, items that were added
five years ago. If the item is not deleted you can read the change
feed as far as the origin of your container.
Change feed is not available for your requirements.
My idea:
Use Azure Function Cosmos DB Trigger to collect all the operations in your specific cosmos collection. Follow this document to configure the input of azure function as cosmos db, then follow this document to configure the output as azure queue storage.
Get the ids of changed items and send them into queue storage as messages.When you want to query the changed item,just query the messages from the queue to consume them at a specific unit time and after that just clear the entire queue. No items will be missed.
With your approach, you can get added/updated documents and save reference value (_ts and id field) somewhere (like blob)
SELECT * FROM collection WHERE userId=[some-user-id] AND _ts > [some-value] and id !='guid' order by _ts desc
This is a similar approach we use to read data from Eventhub and store checkpointing information (epoch number, sequence number and offset value) in blob. And at a time only one function can take a lease of that blob.
If you go with ChangeFeed, you can create listener (Function or Job) to listen all add/update data from collection and you can store those value in some collection, while saving data you can add Identity/version field on every document. This approach may increase your cosmos DB bill.
This is what the transaction consistency levels are for: https://learn.microsoft.com/en-us/azure/cosmos-db/consistency-levels
Choose strong consistency and your queries will always return the latest write.
Strong: Strong consistency offers a linearizability guarantee. The
reads are guaranteed to return the most recent committed version of an
item. A client never sees an uncommitted or partial write. Users are
always guaranteed to read the latest committed write.

How to get the custom updates in telegram

I try to use https://api.telegram.org/bot<token>/getupdates to get updates from telegram with robot, and how can I get custom updates?
Such as, I want to get updates from one telegram group, and in specified time?
Currently there's no way to do that.
You have to process all the updates from the API server in Telegram-specified format. The only thing you can provide as a query filter is an offset parameter.
UPD
If the problem is that you always receive the same set of updates, the reason is that you're specifying incorrect offset parameter for getUpdates method.
From the API docs page:
In order to avoid getting duplicate updates, recalculate offset after each server response
So offset must be different every time you call getUpdates.
How to calculate offset for every call:
getUpdatesrequest returns an array of Update objects.
Every Update object has a update_id property. Iterate over this array, find and store the maximum update_id in a variable (max_upd_id for example).
Use max_upd_id + 1 as a new offset in the next getUpdates call.
For the very first call of getUpdates use offset=0.

Resources