Delete all Data belonging to user - ios

I am rebuilding a social media app like Instagram.
My user can decide to delete their account and then I would like to automatically delete all things belonging to the user.
Most of the stuff I can delete easily, but things like posts is where I struggle because the uid is just a sub child of the key where the post is saved into.
My Database tree:
"Feed" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : {
"-KjTBFFE5QzktG1IT5u0" : true,
"-KjTHFNe1RRS8Ly6bKsA" : true,
"-KjY30xwWA2IJBwlvyzf" : true
}
"myPosts" : {
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : {
"-KjTBFFE5QzktG1IT5u0" : true,
"-KjTHFNe1RRS8Ly6bKsA" : true,
"-KjY30xwWA2IJBwlvyzf" : true
}
"posts" : {
"-KjTBFFE5QzktG1IT5u0" : {
"bookmarkCount" : 0,
"caption" : "Toll",
"commentCount" : 1,
"creationDate" : 1.494081403379004E9,
"hoursSinceUpload" : 0,
"likeCount" : 0,
"photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F76192CBE-55F0-4907-889A-849E196D5796?alt=media&token=de675609-4b73-411d-b402-f1ff3db64f79",
"ratio" : 1.502732240437158,
"score" : 16.38698994684219,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-KjTHFNe1RRS8Ly6bKsA" : {
"bookmarkCount" : 1,
"bookmarks" : {
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"caption" : "Traumhaft",
"commentCount" : 0,
"creationDate" : 1.494082976550228E9,
"hoursSinceUpload" : 0,
"likeCount" : 2,
"likes" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : true,
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F306BF7E1-9FEF-493A-ABF8-C0E061E8648F?alt=media&token=128bdd90-023a-49ac-8361-19c02c631183",
"ratio" : 1.502732240437158,
"score" : 166.6491847103437,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
}
"users" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : {
"email" : "user3#mail.de",
"profilText" : "Schreib etwas über dich",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2Fes5fIbnKFpX4szcCbroUqHjJg6E3?alt=media&token=ce8d8722-39bc-457a-8149-e51c837ef0a3",
"username" : "Blondine",
"username_lowercase" : "blondine"
}
My function where I delete data
static func removeUserData() {
let user = Auth.auth().currentUser
let uid = API.User.CURRENT_USER?.uid
Database.database().reference().child("users").child(uid!).removeValue()
Database.database().reference().child("Feed").child(uid!).removeValue()
Database.database().reference().child("Favoriten").child(uid!).removeValue()
Database.database().reference().child("LikesFromUsers").child(uid!).removeValue()
Database.database().reference().child("post-comments").child(uid!).removeValue()
Database.database().reference().child("notification").child(uid!).removeValue()
Database.database().reference().child("followers").child(uid!).removeValue()
Database.database().reference().child("following").child(uid!).removeValue()
Database.database().reference().child("LikesCommentsFromUsers").child(uid!).removeValue()
Database.database().reference().child("comments").child(uid!).removeValue()
user?.delete(completion: { (error) in
if let error = error {
print(error.localizedDescription)
} else {
print("success")
}
})
}
I would love to iterate through all posts and look for every post which contains the uid of the current user and then delete these posts.
Thanks in advance :)

I would build a server task that can run this asynchronously, removing the responsibility from the mobile device. If the app crashes or loses connection, you'll get a severely broken data set. You need to be able to run it in a stable and verifiable environment. This inherently solves your problem as well, since now you can (at your server's leisure) cycle through and delete all posts owned by the user.
As far as your app is concerned, you'll just need to call a single API after validating that the user wants to delete their account, and voila.

Related

Reading data from Firebase RTDB using Flutter has different behavior on Android and iOS

I'm experiencing a behavior where the following call behaves differently when executed for iOS and for Android.
In Android, the following .get() call returns the expected snapshot from the chatRoomID path. However, in iOS, .get() ends up returning a snapshot of the whole node under myUser.userID.
It seems for iOS, the second child node path is disregarded...
DataSnapshot snapshot = await chatsRef
.child(myUser.userID!)
.child(chatRoomID)
.get();
print(snapshot.value);
JSON:
{
"chats" : {
"oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : {
"c00dca80-9077-11ec-855a-910961fc4253" : {
"chatAdmin" : "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
"chatImage" : "https://images.pexels.com/photos/887827/pexels-photo-887827.jpeg?auto=compress&cs=tinysrgb&h=650&w=940",
"chatName" : "chef",
"chatRoomID" : "c00dca80-9077-11ec-855a-910961fc4253",
"isActivityChat" : false,
"isGroupChat" : true,
"lastMessage" : {
"lastMessage" : "Hey",
"lastMessageTime" : "2022-02-18 00:00:56.992308",
"messageID" : "-MwAC5BUz3GKPmkA1SSQ",
"nKDsrLrcU0PgtEDV5tKpMumSDuu1" : "true",
"oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : "false",
"psJQRp96VGWIjTDpNpMUShPNWa82" : "true",
"sendBy" : "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
"senderName" : "Emily"
},
"muted" : {
"nKDsrLrcU0PgtEDV5tKpMumSDuu1" : false,
"oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : false,
"psJQRp96VGWIjTDpNpMUShPNWa82" : false
},
"users" : {
"nKDsrLrcU0PgtEDV5tKpMumSDuu1" : true,
"oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : true,
"psJQRp96VGWIjTDpNpMUShPNWa82" : true
}
},
"nKDsrLrcU0PgtEDV5tKpMumSDuu1_oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : {
"chatRoomID" : "nKDsrLrcU0PgtEDV5tKpMumSDuu1_oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
"isActivityChat" : false,
"isGroupChat" : false,
"lastMessage" : {
"lastMessage" : "Shut",
"lastMessageTime" : "2022-02-18 00:01:30.161511",
"messageID" : "-MwACDHlTWpQhhQFh9k8",
"nKDsrLrcU0PgtEDV5tKpMumSDuu1" : "true",
"oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : "false",
"sendBy" : "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
"senderName" : "Emily"
},
"muted" : {
"nKDsrLrcU0PgtEDV5tKpMumSDuu1" : false,
"oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : false
},
"users" : {
"nKDsrLrcU0PgtEDV5tKpMumSDuu1" : true,
"oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : true
}
}
}
},
}
As discussed in the comments
You should be getting the same behavior on both iOS and Android, as the underlying SDKs should work the same on those platforms. That said, since the FlutterFire libraries wrap the native SDKs and the get() API is relatively new, it might be that there is an unintended difference between how the iOS and Android SDKs implement it.
If that is indeed the case, you might want try and see if once() works for you. While it has an annoying side-effect in an edge-case (see here), the once API itself is much older, so more likely to be stable across platforms.
Update: I'm having a really hard time reproducing the problem. I've imported your JSON into a database of mine, and then run this code on startup of my app:
FirebaseDatabase database = FirebaseDatabase.instance;
var chatsRef = database.ref('71163140/chats');
var threadRef = chatsRef.child('oF1b6J4Hz3NGzRb9RmSVFGJdcYi1').child('nKDsrLrcU0PgtEDV5tKpMumSDuu1_oF1b6J4Hz3NGzRb9RmSVFGJdcYi1');
DataSnapshot snapshot = await threadRef.get();
if (snapshot.value != null) {
print('get: ${snapshot.value}');
}
DatabaseEvent event = await threadRef.once();
if (event.snapshot.value != null) {
print('once: ${event.snapshot.value}');
}
So it reads a single chat thread out of the data you shared with both get() and once(), and then prints what it gets. Both on iOS and Android, I never see the c00dca80-9077-11ec-855a-910961fc4253 thread showing up in my output, I only get the chat thread where "isGroupChat" : false,.
Can you update the code or data in your question to show how I can get the same faulty result as you get?

Firebase rules access to data

I'm going to create app to share photo albums, using firebase.
Now I've issue with securing common objects.
My data object is
"Album" : {
"AbAY6YVhy6MLyvVjyYC517v62o22" : {
"-KeD0I9C-esXW2zA4uH_" : {
"backgroundPattern" : 0,
"collaboratorsIDS" :
[ "cS5O4Klt8CXrrKLJPVkHMaSTltW2","J55nZlr4SSPHL5GW7c7yrUkbAUl1", "LQ5mNECXAMQi9AoLCXh8GMsihf12" ],
"date" : "2017-03-02",
"direction" : 2,
"imageUrl" : "",
"ownerID" : "AbAY6YVhy6MLyvVjyYC517v62o22",
"scrapBookID" : "-KeD0I9C-esXW2zA4uH_",
"title" : "Test"
}
}
And question is, how to set .read and .write rules for albums. Main point is that collaboratorsIDS is user ID's that should have access to album.
"Album": {
"$albumId" : {
"$pushKey" : {
".read":"data.child('collaboratorsIDS').val().contains(auth.uid)"
}
}
With this, you can allow access to your node for collaboratorsIDS

In the iOS SDK (Swift 3.0), Firebase Database Queries that make use of "queryOrdered/queryEqual", don't work as expected

When running the code below, I get an empty response, even though the corresponding data is there:
self.ref?.child("play-data/calories/GC5g4RUmy0WTTL5w3jSobefa9Ft2").
queryOrdered(byChild: "parentId").
queryEqual(toValue: "-KcpS62MR-73MozKJEVt").
observeSingleEvent(of: .value, with: { (snapshot) in
print("ITEMS \(snapshot.childrenCount)")
}) { (error) in
print("ERROR :: \(error)")
}
The data looks like this:
{
"play-data" : {
"calories" : {
"GC5g4RUmy0WTTL5w3jSobefa9Ft2" : {
"-KcpTSo0KrnNIzmAAD9O" : {
"endTime" : 1486955567572,
"id" : "-KcpTSo0KrnNIzmAAD9O",
"parentId" : "-KcpS62MR-73MozKJEVt",
"startTime" : 1486955550331,
"value" : 1.328500509262085
},
"-KcpTT---0Zu-0eTd4a8" : {
"endTime" : 1486955627572,
"id" : "-KcpTT---0Zu-0eTd4a8",
"parentId" : "-KcpS62MR-73MozKJEVt",
"startTime" : 1486955567572,
"value" : 4.62333345413208
},
"-KcpTT-1SvZrScKdceLC" : {
"endTime" : 1486955636994,
"id" : "-KcpTT-1SvZrScKdceLC",
"parentId" : "-KcpS62MR-73MozKJEVt",
"startTime" : 1486955627572,
"value" : 0.7260898947715759
}
}
}
So based on the data, it should print 3 but does 0. Permissions are configured correctly since I have Android and web implementations that work fine with this data. Any ideas?
OK, looks like this was the result of my local and cloud versions of the data being out of sync and therefore the inconsistent results during testing (where I had to run tests, replace the post-test data with an older backup, repeat) I fixed these issues by adding this line to my init code:
ref?.child("play-data").keepSynced(true)
I already had this one before:
db?.persistenceEnabled = true
Where ref and db are references to FIRDatabaseReference/FIRDatabase.

Create push notification when value in firebase database change

I want to send a push notification to the user when a value in my firebase database change. this is my database
{
"Battles" : {
"00000111-062B3333-4046-4FB4-AA37-C2B05853E497" : {
"BattleProgress" : "",
"Player1" : "lzsPuNwHbIZI1J8k40FspYRV4XQ2",
"Player2" : "tHNBif9csWNCOuftAGLAqvLWNUw1",
"Score" : "0-0",
"Turn" : 1
}
},
"users" : {
"lzsPuNwHbIZI1J8k40FspYRV4XQ2" : {
"Coins" : 1,
"Dollars" : 0,
"FBID" : “ID”,
"GamesLost" : 0,
"GamesWon" : 0,
"name" : “Name”
},
"tHNBif9csWNCOuftAGLAqvLWNUw1" : {
"Coins" : 0,
"Dollars" : 0,
"FBID" : “ID”,
"GamesLost" : 0,
"GamesWon" : 0,
"name" : “Name”
}
}
}
So lets say, the value of "Turn" changes, then I want a push notification sent out to the player whos turn it is. But how can I check if the value of "Turn" changes when the user shuts down the app?
I've read a bit about Firebase Cloud Messaging, but cant seem to find the answar...
You can do this with Firebase using Cloud Functions. Check out https://firebase.google.com/docs/functions/use-cases and https://firebase.google.com/docs/functions/database-events for more information.

Firebase: Searching child nodes that have a unique ID

I'm fairly new to Firebase and have a rankings app, where my structure currently looks like the following:
{
"Rankings" : {
"-KFGX5H3rLSnpPvupakm" : {
"Sports Teams" : {
"Red sox" : 1,
"Warriors" : 3,
"Yankees" : 2
}
},
"-KFGZkwAIl817CLDLmMp" : {
"Beers" : {
"Bud light" : 3,
"Coors" : 2,
"Pbr" : 4
}
}
}
}
I'm using childIDs so I can sort these chronologically. If I want to search rankings by name, how can I bypass the child ID to do so?
For instance, if a user searches for rankings using the term "Sports," how can I traverse my Rankings tree by searching for all rankings containing "Sports"?
This type of deep querying on dynamic paths is not possible with Firebase (nor with many other NoSQL databases). What you'll need to do is set up a so-called index, that maps the keys that you want to search for to the values that you want to find.
{
"Rankings" : {
"-KFGX5H3rLSnpPvupakm" : {
"Sports Teams" : {
"Red sox" : 1,
"Warriors" : 3,
"Yankees" : 2
}
},
"-KFGZkwAIl817CLDLmMp" : {
"Beers" : {
"Bud light" : 3,
"Coors" : 2,
"Pbr" : 4
}
}
},
"SearchTerms": {
"Red sox" : {
"-KFGX5H3rLSnpPvupakm": true
},
"Warriors" : {
"-KFGX5H3rLSnpPvupakm": true
},
"Yankees" : {
"-KFGX5H3rLSnpPvupakm": true
},
"Bud light" : {
"-KFGZkwAIl817CLDLmMp": true
},
"Coors" : {
"-KFGZkwAIl817CLDLmMp": true
},
"Pbr" : {
"-KFGZkwAIl817CLDLmMp": true
}
}
}
This process is called denormalizing your data and it's described in this blog post, in the Firebase documentation on structuring data and in this article on NoSQL data modeling. And in probably half a dozen similar answers I've given recently.
I was able to get the values of the child node-id's.
Here is my sample code:
LOCATION_URL.queryOrderedByChild("email").queryEqualToValue(FIRAuth.auth()?.currentUser?.email).observeEventType(.Value, withBlock: { snapShot in
let enumerator = snapShot.children
while let rest = enumerator.nextObject() {
var shot = rest.childSnapshotForPath(rest.key)
// child node ID
print(shot.key)
}
})
I hope this helps you..
Best regards,
Nazar Medeiros

Resources