Is there any way I can prevent the database to insert values with empty(null) string.
For Eg.
/path/to/certainString/value
As in the above path, somehow if certainString = "" then the database stores value without a proper child
-Root
--Key1
---value1
---value2
---value3
...
So if Key is empty, then it inserts values something like below
-Root
--value1
--value2
--value3
--Key1
---value1
---value2
---value3
...
Is there anyway I can prevent such condition at all paths using Database Security Rules
There's a big distinction between a null value and an empty string in the Firebase Realtime Database. Firebase can store an empty string, but it cannot store a null value. Trying to store null in a path effectively deletes that path from the database. Since the two cases are treated different by Firebase, you'll need to handle them separately in your rules too.
You can prevent a user from storing an empty string with this rule:
".validate": "data.isString() && data.val().length > 0"
Also see the documentation on the RuleDataSnapshot.length property.
To prevent the user from writing null, you need to prevent the user from deleting the data at the path. While this is possible, you can't do it with a validation rule, as those are not triggered by a delete operation. So to prevent data deletion/null values, we use a write rule:
".write": "newData.exists()"
Also see the documentation on the RuleDataSnapshot.exists() method.
Related
I am creating a Social app and want to track if a username already exists or not. The username list is supposed to grow in future and the way I was doing it now was a key value pair of <string,bolean> like this:
name1: true,
name2: true
all the above data was to be stored in a single document and whenever I want to see if a user exists I would call this document and check accordingly. But here's the problem, firebase max document size is 1MBs and as the users grow this can be problematic, so wanted to know from firebase experts that what's the best way to solve this use case in firestore or realtime database but since I need to query exists maybe realtime db won't suit that well.
Note that I don't want any of firestore querying capabilities but only to check if an entry exists in the record or not and if not just add it.
The Realtime Database doesn't have a 1MB limit (since it has no concept of a document, and everything is just a tree of JSON), so I'd typically use that for the index of user names.
Checking whether a name exists is pretty simple there too, and in JavaScript would look something like:
const usernames = firebase.database().ref('usernames');
usernames.child('name1').once((snapshot) => {
if (snapshot.exists()) {
...
}
});
I am currently setting up my realtime firebase database to my iOS application.
It is my first time trying to structure user data in a firebase database, and I am really, really struggling with understanding a few key things.
A bit of context to my application's database needs:
When a new user is created, the attributes assigned directly to the user are:
Age
Email
Username
Nationality
Later on, the user needs the option of creating personal diaries!
Each of these diaries being arrays/lists of objects... Where each object in a diary furthermore holds a few attributes in a list/array.
After reading everything I could find anywhere, I picture my database something like this:
I am terribly sorry if it becomes too specific - I will try to make the question as open as possible:
My question is:
How to create the different "children" programmatically and how to find the keys leading back to them, so I can refer to them at other times again? (when editing an attribute in a child).
A few methods I have tried:
setValue([ArrayOfObjects]) --> This creates the desired array, but I can't seem to find e.g. index 3 in this array, to allow user to change his/her email later on.
childByAutoID() --> This as well creates my array, but gives several other problems: User can only store one diary, still can't find the paths to specific indexes...
setValue(), andPriority() --> Can't seem to make the priority function. (Is this function also outdated??)
And a few more...
If anyone can tell me how to achieve just the first few steps in setting up my database structure, I will be forever grateful - I have spent literally all day on it and I am not moving forward ...
Or, at least tell me, if I am on the right track regarding my desired setup of the database. Is it flat enough? Is there a smarter way to store all these user created lists?
Thank you so much! :-)
I don't know Swift so my examples are in Dart but the methods are similar I believe.
First off, I would split the Users node into two. One to hold the user data, which is normally pretty static, and the other to hold the diaries. You would use the same uid key as reference to both. This way you have less nesting to worry about and therefore it is much easier to CRUD the data. If you are using Firebase to authenticate your users then I would use the unique key that Firebase creates for each user as the keys for these two nodes.
Then...
To create a user data node record the Dart code would be something like:
referenceUserData.child(<authenticated user id>).set({
"age": <age value>,
"email": <email value>,
"name": <name value>,
});
To create a user diary node object record the Dart code would be something like:
referenceUserData.child(<authenticated user id>).child(<diary key>).child(<diary object key>).set({
"object info value 1": <object value>,
"object info value 2": <object value>,
"object info value 3": <object value>,
});
You could also create all the object records at once by writing them as a List (array) using .set().
You also need to decide what your diary key should be. You could use Firebase to generate a unique key by using .push().set().
To read eg. the user data then your call could be:
referenceUserData
.child(<authenticated user id>)
.once()
.then(
(DataSnapshot snapshot) {
print(snapshot.key);
if (snapshot.value != null) {
print(snapshot.value);
<code to process your snapshot value>
}
};
BTW, 'priority' is legacy from the early days of Firebase RTDB so I wouldn't try to use it.
I have an existing data model that has a unique indexed string field that defaults to an empty string.
I added an $attributes property to the model to default it to an empty string when creating a new object. That works just fine.
However when updating the object and the field remains empty, it will fail since the field is returned as null and the DB field is not nullable. I am not sure of the impact of making that field nullable(). Too much code to dig through so I can't change it.
I am thinking I can observe for an event, and change the value from null to empty string there, but I would rather take care of this in Nova.
Is there anyway to tell Nova an empty field should be saved as an empty string?
Short version: no.
Long version:
This cannot be set in Nova. An empty string will be passed as null in the HTTP request. This behaviour is part of Laravel's core. The only way to make sure it isn't passed as an empty string from Nova is to put form validation on it and make it a required field.
If you don't mind changing code on the Laravel app level, you can disable this behaviour by removing the ConvertEmptyStringsToNull middleware in your app's Kernel.
/app/Http/Kernel.php
protected $middleware = [
...
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, // remove this line
];
However, if the DB field isn't nullable, the field has to have a value anyway right? I'd suggest putting an accessor on the model to check for null values:
public function setMyFieldAttribute($val)
{
$this->attributes['my_field'] = $val ?? '';
}
Or, if you want to be really certain it always has a value, add an observer for the saving event (as you already mentioned), and make sure the field has a value before the data is actually saved.
When querying records that current user created, the value in currentUserRecordID.recordName is "____defaultOwner__"
Is there a way to tell cloudKit to return the real hash key instead of "____defaultOwner____" in the results ?
I consider to replace "manually" the defaultOwner string with currentUserRecordID.recordName, but before doing that, I want to check maybe there is the "simple" way that cloudKit server will do this.
I want to only update the values email, firstname and lastname if they are blank.
I need this so that if the user decides to change these in the settings, they are not overwritten every time the user logs in with facebook.
Any solutions to check if the fields are blank without a datasnapshot? Trying to maximise efficency.
Current code when user signs in with facebook?
Database Structure for each user:
One way to do this is using a firebase transaction.
A transaction allows you to check the current value of a DB reference before you set/update it. It's main use case is preventing multiple concurrent updates from multiple sources but it can be used for this case as well - read and then write.
In the transaction block you get the value of the DB ref you're transacting on & can check that the value is null (hence 'create' case) -> then update it as required and return TransactionResult.success(withValue: newData).
If the object is already set you simply abort the transaction with TransactionResult.abort() and no write to the DB is executed.
Another option, that doesn't require a read/write, is to set a Firebase database rule on the relevant ref that will only allow write if the previous value was null:
"refPath": {
".write": "data.val() == null && newDataval() != null"
}
Writing a second time to the DB for an existing ref will fail.
I'd go with the transaction - more expressive of the requirement in the client code.
In firebase the only way you have to check if the current value of your fields in your database are empty is to fetch them before you are setting them.
You can check the field is empty only by fetching them.Then Use this code to update a particular value
ref.child("yourKey").child("yourKey").updateChildValues(["email": yourValue])