How can I avoid a firebase data sending collision?

I built a poll application, anyone can add polls and answer polls (here’s a link: https://play.google.com/store/apps/details?id=com.point.Surveys ) But I noticed that if a few people answer together, then a problem arises, how can this collision be prevented? And is there any other database that can get along with it?

Explain your problem in detail.

Show the blocks how you stored the data in firebase and some screenshot

If you want to make a comment system then this can help you:

Also elaborate your problem/question more.

If two users vote (i.e. update the voting tag) then voting is considered for only one user

How do you prevent two people from talking at the same time?

Either you have a chairperson, that tells who can talk when; or everyone listens in first to make sure they would talk only when there is silence.
I suggest you take this second approach. Before sending in the poll answer, the app is querying firebase for a special value “who_is_talking”. If the value of “who_is_talking” is empty, then the app is allowed to make the value of “who_is_talking” to become some unique user_ID associated with whoever is using the app and wants to add a poll answer.
Then the app waits a short while (could be a fraction of a second), and checks the value of “who_is_talking” again. If it matches the user_ID, that means this user successfully requested and obtained the right to speak. The app then enters the pooling value, and returns the value of “who_is_talking” to empty.
If the app got a non-matching user_ID when doing the second read access, this means that someone else got the right to speak, and the app keeps checking it at regular interval until it is returned to empty.

If you want, you can make the system fault tolerant, that is cater for the instance where some one would have obtained the right to speak, and have his app crash, therefore never releasing the access.
You can deal with this by having the “who_is_talking” include a time of request component. If the “who_is_talking” is locked by someone with a time that is inappropriately long (in your case, that could be as short as 5 seconds; how much time should it really take to enter an answer???) then any app is granted the right to set “who_is_talking” to empty, and to proceed with a request to access.

2 Likes

I like to call this type of problem the input “pipeline”, since you have to arrange asynchronous tasks in a line.

@CBVG’s idea is pretty good, but that might slow down the pipeline (by up to 5 seconds, as he said), and the end user would be left hanging for a long time. Our goal is to minimize the time lapse for the end user. Also, the “chairperson” would have to be a separate app, connected 24x7 to the internet. :sweat_smile:

My solution:
Case 1: Voting
This would require an integer to be stored under a tag. Instead, initialize the tag as “tag: [0, “”]”, ie, a list containing an integer and a string.
Whenever a user wants to vote (either upvoting or downvoting; doesn’t make a difference), do this:

Generate a random 32-character hex string, and store it in a global variable.
Get value (tag)
Store the "tag" in another global variable.
When Got Value:
    Store value (tag) {value=[(select item list(value) index = 1]+1), get global random_string}
When Data Changed:
    if tag == get global tag:
        if (select item list(value) index = 2) != get global random_string:
            Store value (tag) {value=[(select item list(value) index = 1]+1), get global random_string}

What this does, is generate a random string with extremely low probability of another user generating the same string. This acts as the “identifier” for the latest voter. After storing the tag with the updated value, if there has been a conflict and the user’s answer was not taken, the identifier would not match. Thus the app would automatically try to store the value again. This would minimize the lag.
Case 2: Polling
tag: [[A:int, B:int, C:int, …, N:int], “”]
The rest is the same.
Case 3: Answering
tag: [[ans1, ans2, ans3, …, ansN], “”]
Again, the rest is the same.

2 Likes

Thanks for the tips, I’ll try to add them in the next update (I’ve been working on another pretty big update for a few months now so I’ll try to upload the update as soon as possible)

I suggested to the Firebase team to add an option that would solve this problem and they said they could do it! (They do not know when it will be ready, but you should catch up from here: Release Notes  |  Firebase)