firebase swift -- users query - swift

I am trying to find a way I could have a query for the users in my application. For example, if my user want to search for a user to add him as a friend. I think I can save all the users in the Firebase database, and then perform a query in the database, but it look very inefficient(and there must be a easier built in method to do it).

".indexOn" is the solution for you!!
If you structure you date like below you would be able to query user!! Here you are able to query user on full_name and reversed_full_name. You can provide whichever child you want to query on. For instance, you can add email field under people and then add "email" in ".indexOn"!!!
"people": {
".indexOn": ["_search_index/full_name", "_search_index/reversed_full_name"],
".read": true,
"$uid": {
".write": "auth.uid === $uid",
"full_name": {
".validate": "newData.isString()"
},
"profile_picture": {
".validate": "newData.isString()"
},
"posts": {
"$postId": {
".validate": "newData.val() === true && newData.parent().parent().parent().parent().child('posts').child($postId).exists()"
}
},
"_search_index": {
"full_name": {
".validate": "newData.isString()"
},
"reversed_full_name": {
".validate": "newData.isString()"
}
},
"following": {
"$followedUid": {
".validate": "newData.parent().parent().parent().parent().child('followers').child($followedUid).child($uid).val() === true" // Makes sure /followers is in sync
}
}
}
Hope this helps. Here's the link to whole security rules, which is provided from Firebase https://github.com/firebase/friendlypix/blob/master/web/database-rules.json

Related

mongo db how to store multi relation like graph

I have to store some users and their group relations like below
So I am planning to create a collection like below
UserGroupRelation Collections
{
"user":String,
"Group":String"
}
example of collections for Super admin users
{
"user":"Adminuser-1",
"Group":"Group1"
}
{
"user":"Adminuser-1",
"Group":"Group2"
}
{
"user":"Adminuser-1",
"Group":"Group3"
}
where user & Group column is indexed and I will run below kind of query
1.Whenever I want to check whether given user has access to the given group
db.UserGroupRelation.find( { user: "Adminuser-1", Group: "Group2" })
2.Also I want to delete all the association whenever we delete group
db.UserGroupRelation.deleteMany({ Group: "Group2" })
3.Also find all the users of a group
db.UserGroupRelation.find( { Group: "Group2" })
4.Find Hierarchy?, with my Approach I am not able to find
But with this approach I am duplicating lot of data also in real time I may have 10000 groups and 1 million user so there would be performance issue. And with this I am not able to maintain a hierarchy like SuperAdmin->SubAdmin->user of same group
I checked with mongo tree but it is not fitting to this requirement. is there a better way to handle this requirement in mongodb .?
This is the structure your graphic requirements show. It does still lead to repetition though so you will need to change it. Read up on one-many relationships.
{
"superAdmin_ID": "001",
"groups": [
{
"_id": "0",
"groupNumber": "1",
"users": [
{
"_userKey": "1023"
"userName": "Fred"
},
{
"_userKey": "1024"
"userName": "Steve"
}
],
"subAdmin": {
"_adminKey": "55230"
"adminName": "Maverick"
},
},
{
"_id": "1",
"groupNumber": "2",
"users": [
{
"_userKey": "1023"
"userName": "Fred"
},
{
"_userKey": "4026"
"userName": "Ella"
}
],
"subAdmin": {
"_adminKey": "55230"
"adminName": "Maverick"
},
},
{
"_id": "2",
"groupNumber": "3",
"users": [
{
"_userKey": "7026"
"userName": "James"
}
],
"subAdmin": {
"_adminKey": "77780"
"adminName": "Chloe"
},
},
]
}
You can also make subAdmin an array if you need more than one subAdmin within a group.

Firebase says that my rules are insecure, why?

I have received an email from Firebase advising me that my security rules are insecure citing: Any user can read/write to your database.
How can this be, I have specified .read and .write rules below. What am I missing? any help would be much appreciated.
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"venues-location": {
".indexOn": "g"
},
"users-compliments": {
"$uid":{
"$uid":{
".indexOn": ".value"
}
}
},
"users-invites": {
"$uid":{
"$uid":{
".indexOn": ".value"
}
}
},
"users-location": {
".indexOn": "g"
}
}
}
".read": "auth != null",
".write": "auth != null",
These above rules are default rules. According to firebase documentation They allow full read and write access to authenticated users of your app. They are useful if you want data open to all users of your app but don't want it open to the world
It is essential that you configure these rules correctly before launching your app to ensure that your users can only access the data that they are supposed to.
{
"rules": {
"foo": {
".read": true,
".write": false
}
}
}
Here's an example of a rule that grants write access for authenticated users to /users//, where is the ID of the user obtained through Firebase Authentication.
{
"rules": {
"users": {
"$uid": {
".write": "$uid === auth.uid"
}
}
}
}
"auth != null" is not enough. It means anyone who is authenticated can read/write to another user's data. You probably want to add something like:
".write": "auth.uid == $uid" under the $uid nodes.
to only allow the authenticated user to access their own data and not another user's.

How to forbid rewriting data if it exists

I add user in table "users" after authorization. Also I will add to this user some values, which I don't want to be overrided.
ref.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).setValue(["username": "MyName"])
Rules
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"users": {
".write": "!root.child('users/'+auth.uid).exists()",
".read":true,
"positive": {
".read": true,
".write":false,
},
"negative": {
".read": true,
".write":false,
},
}
}
}
removes old data and put a new.
I want to write rule on server side, which will ignore setting value if it already exists.
If you call updateChildValues(), the properties you specify will be updated:
ref.child("users")
.child((FIRAuth.auth()?.currentUser?.uid)!)
.updateChildValues(["username": "MyName"])
See the Firebase documentation on updating specific fields.
Your rules will not work, since you cannot take away a permission that you've given on a higher level in the tree. See the Firebase documentation on the cascading of permissions.
To ensure a user always has certain properties, use a rule on the user's node:
"users": {
"$uid": {
".write": "newData.hasChildren(['certain', 'properties])",

Update existing fields in mongodb

For example:
db.getCollection('user')
.update(
{
"userDetails.username": "ky"
},
{
"$set":
{
"active": false,
"admin": false,
"phone": "08432808"
}
})
In the above code, if the document doesn't have the "active" field, mongodb will insert that field for you. I would like to get some error message in return in such situations, how can I achieve that?
You could achieve something like this using a foreach, filtering what you want to check and then verifying whether the property exists if not throw an exception. Can't say I'm a fan of this, I'd rather have the application logic verify the record exists and have a decision there of whether to update or do another action.
db.user.find({"userDetails.username": "ky"}).forEach(function(doc){
if (!doc.hasOwnProperty('active')){
throw "No active property";
}
else{
db.user.update({ _id: doc._id }, { "$set": { "active": false }})
}
})

Firebase Security for their recommended chat structure implementing lastMessage

So I've come across this thread.
Structuring data for chat app in Firebase
I would just like to give a sample for my firebase db structure ( similar in firebase docs).
{
"chatMetadata": {
"chatroom_id_1": {
"title": "Some Chatroom Title",
"lastMessage": "Some Message",
"timestamp": 1459361875666
"users": {
"uid_1": true,
"uid_3": true
}
},
"chatroom_id_2": { ... }
},
"users": {
"uid_1": {
"chatRooms": {
"chatroom_id_1": true,
"chatroom_id_2": true
},
},
"uid_3": { ... }
},
"chatrooms": {
"chatroom_id_1": {
"m1": {
"name": "uid_1",
"message": "The relay seems to be malfunctioning.",
"timestamp": 1459361875337
},
"m2": { ... }
},
"chatroom_id_2": { ... }
}
}
For me to implement like a recent chat messages. I'll probably need the "/chatMetadata/" data since it has the lastMessage
To query it in client we need the answer in the link above to get it in one reference alone.
//chatMetaDataRef = root of "chatMetadata"
chatMetaDataRef.queryOrderedByChild("users/uid_3").queryEqualToValue(true)
.observeSingleEventOfType(.Value, withBlock: { snapshot in
// Do something here
})
Problem with this is all users should have read access to "/chatMetadata" node for that to work.
Here is my security rule for it
{
"rules": {
".read": "auth.uid === 'someServiceWorker'",
".write": "auth.uid === 'someServiceWorker'",
"chatMetadata": {
"$chatroomId":{
".read": "data.child('users/'+auth.uid).exists()"
},
".read": "auth != null"
},
"chatrooms": {
"$chatroomId": {
".read": "root.child('chatMetadata/'+ $chatroomId + '/users/'+auth.uid).exists()",
}
},
"users": {
"$userId": {
".read": "auth.uid === $userId"
}
}
}
}
Now my question is how should we implement the security rule for this one such that users shall not have access to all chatMetadata(because if i remove "auth!=null", my query above will not work. Or if it is not possible how should we restructure the data such that we can query it with one reference alone?
P.S.
Reason for the question is I didn't like the idea that I will loop over "users/$uid/chatrooms" and query each reference I receive from it. Like the 2nd answer in the link above.
for chat in listOfChatsUserIsIn
ref.child("chatMetadata").child("\(chat)").child("lastMessage").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
lastMessage = snapshot
// do something here
}