Limit the retrieve of documents from Firebase on Flutter - firebase

I would like to learn how can I limit the retrieved document from Firestore quantity for each user. Is there any possible way to achieve this with shared preferences? Because I do not use a login or registration protocol for the user. I am using shared preferences in order to recognize the user.
Single user should retrieve only 1 document each day. This is what I want to implement.
Also I would like to learn that how can I save and show fetching date of the document?

You can do the following in Firebase:
Query query = cities.orderBy("name").limit(3); // descending order
Query query = cities.whereGreaterThan("population", 2500000L).orderBy("population").limit(2); // ascending order
You can take a look at the documentation, there are the corresponding methods.
https://firebase.google.com/docs/firestore/query-data/order-limit-data

Related

How to store additional data in Flutter and firebase Authentication method

Good Morning,
I have a simple query, I am using firebase Authentication as a sign-in/ signup method to my flutter app, what is the right method if I want to store additional data, such as name, age and etc...
If you look at the class User that is defined in User.dart for instance that ships with the Firebase SDK for Flutter, you'll see various properties of the User class, including but not limited to:
String? get displayName
String? get email
bool get emailVerified
bool get isAnonymous
UserMetadata get metadata
You might see the metadata property and think Aha! Maybe I can put my extra data there, but if you look at that class' properties and code you'll soon realize that it's not going to allow you to store additional properties in it either.
So the User in Firebase is not the right place to store additional information about that user itself! That's the take-away I want you to get from this answer.
The right way to go about doing this is to store your additional information per user inside your Firestore Database. Create a simple collection and name it something along the lines of UserInfo and in there per user-id, store the additional information that you need per user, and add a field to every object in that collection named user-id and store the user.id in that field. That way you can always do a look-up of user information per user.id.
As i understand your problem to store additional data of a user after login. For this you can use Firestore database and create collections for the fields like- name, age and etc...
https://pub.dev/packages/cloud_firestore
Have a look into this library.
https://medium.com/firebase-developers/cloud-firestore-basics-in-flutter-68c7ec42eeca
To understand firestore go through this article.

Cloud firestore - Order by nested data

I am new to Firebase cloud firestore. My database structure looks something like in the picture below. So, basically I have got a document for 'Liked' which tracks the timestamp at which user has liked the content. It has got 'chapter' as subcollection and inside each chapter there are sub-chapters which has the actual timestamp. Now I want to retrieve all the liked data ordered by the timestamp. I am not sure how can I achieve this!
You may use orderBy() to specify the sort order for your data like shown in the following example:
db.collection("liked").orderBy('timestamp').get()
I would also suggest you to follow this doc, it demostrates how to set up Cloud Firestore, add, read data and secure data.
UPDATE
I created the following database to replicate your scenario:
reprod(collections)/
test1(document)/
liked(collections)/
0(document)/
type(filed)
To stream the timestamps in ascending order I iterated manually to the doc and fetched the data ordered by timestamp:
reprod = db.collection(u'reprod').document(u'test1').collection(u'liked')
timestamps = reprod.stream()
for doc in timestamps:
print(f'{doc.id} => {doc.to_dict()}')
To do that I used the Firestore documentation on how to retrieve data and how to order data.

increment document id by timestamp in firestore

My cloud firestore database has an "orders" collection and in HTML I have a 'save' button to add document(s) into that "orders" collection upon clicking. Now, using add will assign auto-generated ID for each document.
What if I want to customise such ID by timestamp? So that the document created yesterday will be assigned an index as '1', and the following document created will be '2', etc...
What you're trying to do is not compatible with the way Cloud Firestore was designed. Firestore will not assign monotonically increasing numbers for document IDs. This just doesn't scale massively as required by Firestore and would introduce performance bottlenecks.
If you want to be able to sort documents by timestamp, the best strategy is to add a timestamp field to each document, then use that field in an ordered query.
Note that you could try to write a lot of code to get this done the way you want, but you are MUCH better off accepting the random IDs and using fields to filter and order data.
in some case, when you need to save several docs in different collection due to an event occurs, it's better to same all docs with same id in different collections with single firestore server's timestamp. you get the timestamp like below:
const admin = require('firebase-admin')
const ts = admin.firestore.Timestamp.now().toMillis().toString()
by doing this, when you need to read all those docs, you only need to query once to get timestamp, then read all other doc by timestamp directly.
it should be faster than query the timestamp inside document fields for each collections

Firebase Cloud Firestore request

I have a MESSAGERECAP collection which includes a unique id for each message, the id of the receiver of the message, the id of the sender and the message itself. In my application, when the user clicks on a friend to chat with him, I want the chat activity to start with the list of messages they have both sent.
I did this but obviously it does not give the desired result :
Query query = messageRef.orderBy("mssgId",Query.Direction.DESCENDING);
// with messageRef a reference to the MESSAGERECAP collection
Here is an overview of my database
You are getting the whole list because you are not filtering the data, just ordering it. If you check the Querying documentation for Firestore, also provided by #FrankVanPuffelen on the comments of your question, you can see that you have to use .where() to filter the data that you want to retrieve.
Also, as pointed out by #Jay in the comments, you can use Compound Queries to create a logical AND on your query to retrieve the data you want.
So if you do something like:
messageRef.where("senderId", "==", [currentUserId])
.where("receiver_id", "==", [receiverUserId])
.orderBy("mssgId",Query.Direction.DESCENDING)
When you execute this query you will get all the messages sent by the current user to the receiving user of the correponding id.

Firebase Firestore Documents changes history (like Activity log/ History for changes in each Doc)

I'm trying to make an Activity log system or history for my docs, so every time a field is modified in a document i want to record or save that so i can see after changes history made on each document.
how i can achieve that ? i don't want to save the full doc on each change and then have tons of duplicated docs, if possible i just want to get the changed field (ex. name: 'john' -> name: 'jack').
i don't want to save the full doc on each change and then have tons of duplicated docs
Once a document has changed it becomes a new document. So you won't have duplicate documents unless you make changes that were previously made. Please also note that in Cloud Firestore there are no field-level permissions or access to a document. It's the entire document, or nothing. So if you want to change a field within a document for example from:
userName = "John"
into
userName = "Jack"
You'll will get the entire document and not only the userName property that has been changed.
Cloud Firestore listeners fire on the document level. There is no way to get triggered with just particular fields in a document.
If you want to get notified only of specific fields, consider adding an extra collection with documents that only contain those fields. This sort of data duplication is quite common in NoSQL solutions such as Firestore and for that, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding. It is for Firebase real-time database but same principles apply to Cloud Firestore.
For a database schema you can also take a look at my answer from this post.
The best way to achieve something like this is to store the before and after changes happening to the doc, in a new document, which you can add in a subcollection. The changes are available with cloud functions onUpdate trigger. I have written in depth about this topic on my blog, have a look.
https://blog.emad.in/audit-logs-for-firestore-documents/
You can obtain this by creating a cloud function that triggers on all document updates in all collections:
--trigger-resource=projects/$PROJECT_ID/databases/(default)/documents/{collection_id}/{document_id}
In the cloud function you can obtain all the updated fields and their values through the data object.
Python example:
def main(data, context):
# Extract resource
resource = context.resource
resource_split = resource.split('/')
collection_name = resource_split[-2]
document_id = resource_split[-1]
# Get old fields
data_old_values = data['oldValue']
data_old_values_fields = data_old_values['fields']
# Get updated fields
data_updated_mask = data['updateMask']
data_updated_fields = data_updated_mask['fieldPaths']
# Get new field values
data_new_values = data['value']
data_new_values_fields = data_new_values['fields']
# `data_updated_fields` is a list of the fields that has been changed
# `data_old_values_fields` is a dictionary with the old values of the document
# `data_new_values_fields` is a dictionary with the new values of the document

Resources