Firebase data validation based on timestamps - firebase

I need a validation rule that checks if the end date is after the start date, so the period is valid. I have found a couple resources, but I couldn't use them to get what I need. Perhaps for someone else it is of some use.
https://medium.com/#khreniak/advanced-examples-of-using-cloud-firestore-security-rules-9e641d023c7e
End-date greater than start-date validation android
Basically, I have document coming in in cloud firestore and I need to check if the value dateEnd > dateStart. Both come from the same request. I would rather store the values as day/month/year instead of storing them as a timestamp value. However, if there is no other solution than to use timestamps, I could use that.
I can't get any further than this:
match /organisations/{orgID}/people/{userID} {
allow create: if(dateEnd > dateStart)
}
Thanks in advance for your help

If you use a date format like YYYYMMDD (which allows to lexicographic order dates), the following should do the trick. It would also work with timestamps in milliseconds.
match /organisations/{orgID}/people/{userID}
allow create: if request.resource.data.dateEnd > request.resource.data.dateStart;
}
As explained in the doc, "When writing data ... the request.resource variable contains the future state of the document".
I would suggest you watch the official video about security rules, a must watch...
If you absolutely need to store the values as DD/MM/YYYY in the Firestore document you should have two pairs of fields: a dateEnd/dateStart pair of field with format DD/MM/YYYY, and another pair of fields, e.g. dateEndForRules/dateStartForRules with format YYYYMMDD that you only use in the Security rules.

Related

How can I limit and sort on document ID in firestore?

I have a collection where the documents are uniquely identified by a date, and I want to get the n most recent documents. My first thought was to use the date as a document ID, and then my query would sort by ID in descending order. Something like .orderBy(FieldPath.documentId, descending: true).limit(n). This does not work, because it requires an index, which can't be created because __name__ only indexes are not supported.
My next attempt was to use .limitToLast(n) with the default sort, which is documented here.
By default, Cloud Firestore retrieves all documents that satisfy the query in ascending order by document ID
According to that snippet from the docs, .limitToLast(n) should work. However, because I didn't specify a sort, it says I can't limit the results. To fix this, I tried .orderBy(FieldPath.documentId).limitToLast(n), which should be equivalent. This, for some reason, gives me an error saying I need an index. I can't create it for the same reason I couldn't create the previous one, but I don't think I should need to because they must already have an index like that in order to implement the default ordering.
Should I just give up and copy the document ID into the document as a field, so I can sort that way? I know it should be easy from an algorithms perspective to do what I'm trying to do, but I haven't been able to figure out how to do it using the API. Am I missing something?
Edit: I didn't realize this was important, but I'm using the flutterfire firestore library.
A few points. It is ALWAYS a good practice to use random, well distributed documentId's in firestore for scale and efficiency. Related to that, there is effectively NO WAY to query by documentId - and in the few circumstances you can use it (especially for a range, which is possible but VERY tricky, as it requires inequalities, and you can only do inequalities on one field). IF there's a reason to search on an ID, yes it is PERFECTLY appropriate to store in the document as well - in fact, my wrapper library always does this.
the correct notation, btw, would be FieldPath.documentId() (method, not constant) - alternatively, __name__ - but I believe this only works in Queries. The reason it requested a new index is without the () it assumed you had a field named FieldPath with a subfield named documentid.
Further: FieldPath.documentId() does NOT generate the documentId at the server - it generates the FULL PATH to the document - see Firestore collection group query on documentId for a more complete explanation.
So net:
=> documentId's should be as random as possible within a collection; it's generally best to let Firestore generate them for you.
=> a valid exception is when you have ONE AND ONLY ONE sub-document under another - for example, every "user" document might have one and only one "forms of Id" document as a subcollection. It is valid to use the SAME ID as the parent document in this exceptional case.
=> anything you want to query should be a FIELD in a document,and generally simple fields.
=> WORD TO THE WISE: Firestore "arrays" are ABSOLUTELY NOT ARRAYS. They are ORDERED LISTS, generally in the order they were added to the array. The SDK presents them to the CLIENT as arrays, but Firestore it self does not STORE them as ACTUAL ARRAYS - THE NUMBER YOU SEE IN THE CONSOLE is the order, not an index. matching elements in an array (arrayContains, e.g.) requires matching the WHOLE element - if you store an ordered list of objects, you CANNOT query the "array" on sub-elements.
From what I've found:
FieldPath.documentId does not match on the documentId, but on the refPath (which it gets automatically if passed a document reference).
As such, since the documents are to be sorted by timestamp, it would be more ideal to create a timestamp fieldvalue for createdAt rather than a human-readable string which is prone to string length sorting over the value of the string.
From there, you can simply sort by date and limit to last. You can keep the document ID's as you intend.

How to validate incoming data is an array and it contains decimal number using firestore security rules

My client app is sending location data to firestore so i wanna make sure it is in decimal formate if not then not allow to write.
I have it like this,
Collection place and document in random number and feild as loc : [0]:7.8 , [1]:2.7
This currently isn't possible with security rules, as it provides no mechanism for you to iterate a list and check each item in it.
If you want to check if a single value is a number, you can simply check that the client provided a number type value using value is number. So you could check if a known field is a number:
allow write: if request.resource.data.knownField is number;
But you won't be able to do that for every item in a list. You will need a backend to do that.

How to correctly define ID and DateTime fields in Firebase Firestore database?

I am using Firebase FireStore database for the first time and I have the following question.
I have created a calendar collection. This collection will contains document representing events that have to be shown into a Calendar implemented by an Angular application.
So I am defining the following fields for these documents:
id: int. It is a unique identifier of the specific document\event.
title: string. It is the event title.
start_date_time: string. It specifies the date and the time at which the event starts.
end_date_time: string. It specifies the date and the time at which the event ends.
And here I have some doubts:
Is the id field required? From what I know I will have the document UID that will ensure the uniqueness of the document. If not strongly required adopt an id field can be convenient have something like an auto increment field? (I know that I have to handle in some other way the auto increment because FireStore is not a relational DB and doesn't automatically handle it). For example I was thinking that can be useful to order my document from the first inserted one to the last inserted one.
It seems to me that FireStore doesn't handle DateTime field (as done for example by a traditional relational database). Is this assumption correct? How can I correctly handle my start_date_time and end_date_time fields? These field have to contains the date time used by my Angular application? So for example I was thinking that I can define it as string field and put into these fields values as 2020-07-20T07:00:00 representing a specific date and a specific time. It could be considered a valid approach to the problem or not?
Is the id field required?
No fields are required. Firestore is schema-less. The only thing a document requires is a string ID that is unique to the collection where it lives.
There is no autoincrement of IDs. That doesn't scale massively the way Firestore requires. If you need ordering, you will have to define that for yourself according to your needs.
In general, you are supposed to accept the randomly generated IDs that the Firebase client APIs will generate for you. Ordering is typically defined using a field in the document.
It seems to me that FireStore doesn't handle DateTime field
Firestore has a timestamp field type that stores moments in time to nanosecond precision. There is no need to store a formatted string, unless that's something you require for other reasons.

How does Firestore save dates?

I've recently discovered firestore.Timestamp and so I tried to assign firestore.FieldValue.serverTimestamp(); to one and it didn't work. instead it says Type 'FieldValue' is not assignable to type 'Timestamp' which I would say is strange. Shouldn't serverTimestamp() be a Timestamp and not a FieldValue? What would be the purpose of firestore.Timestamp if not to save timestamps to Firestore? Is there a way to get a server timestamp that is compatible with firestore.Timestamp or should I be avoiding timestamps altogether, and just stick to firestore.FieldValue for all my dates?
serverTimestamp() just returns sentinel value that tells the Firestore server that it should use the current time on the server as the value for the field you're trying to set. It doesn't return an actual Timestamp object itself.
The reason why you'd use this is to make sure that dates are being set consistently on the server instead of depending on the clock being correct on the user's device.
If you want to know the current time on the device, just use the native date/time objects provided by the language or operating system.

Firebase: Protect creation_date property of a document

I'm planning to use firebase, but I have security related question.
My documents have creation_date property and it is filled with ServerValue.TIMESTAMP when document created.
Can I be sure that user will not reverse engineer my webapp to somehow insert fake date? And protect this field from future edits.
You can use the request.time variable in the security rules for validating the value of the timestamp. From the reference documentation:
The time variable contains a timestamp representing the current server time a request is being evaluated at. You can use this to provide time-based access to files, such as: only allowing files to be uploaded until a certain date, or only allowing files to be read up to an hour after they were uploaded.
// Allow a read if the file was created less than one hour ago
allow read: if request.time < resource.data.timeCreated + duration.value(1, 'h');
Many functions are provided to write rules using timestamps and durations.

Resources