Firebase how to prevent duplicate entries atomically

I am looking at using Firebase as a data store for user data for a web application. My current thought is to store each user’s data using a timestamp when they join, as a key that references this user’s data. The advantage of this scheme is that it is a simple way to assign unique integer identifiers to users and simplifies the chronological sorting of users.

The drawback, however, is that if two "add user" requests are sent with identical data, the application will happily add two separate entries, which is not suitable. I could mix things around (I'm starting to think that I should use email as a key and prioritize according to the connection data, and not according to my current scheme), but to assume that I do not want to. Is there a way to prevent data duplication?

The naive approach will probably just do something like:

if(!searchFirebaseForUser(data)) { addUser(data); } 

But this is definitely a race condition; it would be easy to make two queries on both queries and not find a single user in the database, and both add. I would like to do this in a transaction, but Firebase transaction support does not seem to cover this case. Is there any way to handle this?

+4
source share
4 answers

You may have to use your username or email address as the key and try to atomically write to this place.

Here is the corresponding code example from a link to a transaction function. In this case, we use wilma as the key for the user.

 // Try to create a user for wilma, but only if the user id 'wilma' isn't already taken. var wilmaRef = new Firebase('https://SampleChat.firebaseIO-demo.com/users/wilma'); wilmaRef.transaction(function(currentData) { if (currentData === null) { return {name: {first: 'Wilma', last: 'Flintstone'} }; } else { console.log('User wilma already exists.'); return; // Abort the transaction. } }, function(error, committed, snapshot) { if (error) console.log('Transaction failed abnormally!', error); else if (!committed) console.log('We aborted the transaction (because wilma already exists).'); else console.log('User wilma added!'); console.log('Wilma\ data: ', snapshot.val()); }); 
+8
source

Are security rules sufficient to ensure uniqueness? I have no idea whether they are atomic or not.

 { "rules": { "users": { "$username": { ".write": "!data.exists()" } } } } 
+4
source

You can use push to automatically generate chronologically incremental identifiers that will not conflict with other clients, even if they are created at the same time (they have a random component).

For instance:

 var ref = new Firebase(URL); var record = ref.push(userInfo); console.log("User was assigned ID: " + record.name()); 
0
source

instead of defining a rule in the fire-base database, the easiest way to prevent duplicate entries is, first of all, to get all the data from the fire-base database and compare it with the data (new data) that you want to keep if it is matched with the previous ones data, then discards the save in the database, otherwise stored in database.check below for clarity.

 public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private BroadcastReceiver mRegistrationBroadcastReceiver; private TextView txtRegId, txtMessage; DatabaseReference databaseArtists; ListView listViewArtists; public static String regId; List<Artist> artistList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtRegId = (TextView) findViewById(R.id.regid); txtRegId.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { displayFirebaseRegId(); boolean flag=false; String tokenId=regId; for(Artist a:artistList) {Log.d("RAaz",a.getTokenId()+" "+tokenId); if(a.getTokenId().equalsIgnoreCase(tokenId)) { flag=true; Toast.makeText(MainActivity.this, "True", Toast.LENGTH_SHORT).show(); } } if(flag) { Toast.makeText(MainActivity.this, "User Already Exists", Toast.LENGTH_SHORT).show(); } else { addArtist(); } } }); mRegistrationBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // checking for type intent filter if (intent.getAction().equals(Config.REGISTRATION_COMPLETE)) { // gcm successfully registered // now subscribe to `global` topic to receive app wide notifications FirebaseMessaging.getInstance().subscribeToTopic(Config.TOPIC_GLOBAL); displayFirebaseRegId(); } else if (intent.getAction().equals(Config.PUSH_NOTIFICATION)) { // new push notification is received String message = intent.getStringExtra("message"); Toast.makeText(getApplicationContext(), "Push notification: " + message, Toast.LENGTH_LONG).show(); txtMessage.setText(message); } } }; displayFirebaseRegId(); databaseArtists = FirebaseDatabase.getInstance().getReference("artist"); artistList = new ArrayList<>();} 

Below is the code to add data to firebase

 private void addArtist() { String name = "User"; String genre = regId; if (!TextUtils.isEmpty(name)) { String id = databaseArtists.push().getKey(); Artist artist = new Artist(id,genre,name); databaseArtists.child(id).setValue(artist); Toast.makeText(this, "Artist Added", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Please enter name", Toast.LENGTH_SHORT).show(); } } 

use onStart to get information from firebase database

 protected void onStart() { super.onStart(); Toast.makeText(this, "On Start", Toast.LENGTH_SHORT).show(); databaseArtists.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { artistList.clear(); for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) { Artist artist = dataSnapshot1.getValue(Artist.class); artistList.add(artist); } } @Override public void onCancelled(DatabaseError databaseError) { } }); } 

finally add the pojo class

 public class Artist { private String artistId; private String tokenId; private String roleName; public Artist() { } public Artist(String artistId, String tokenId, String roleName) { this.artistId = artistId; this.tokenId = tokenId; this.roleName = roleName; } public String getArtistId() { return artistId; } public void setArtistId(String artistId) { this.artistId = artistId; } public String getTokenId() { return tokenId; } public void setTokenId(String tokenId) { this.tokenId = tokenId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } 

}

-2
source

Source: https://habr.com/ru/post/1499983/


All Articles