reglas indexon firestore auth firebase transactions firebase-database atomic

indexon - Firebase cómo evitar las entradas duplicadas de forma atómica



firestore rules (4)

Estoy buscando usar firebase como un almacén de datos para datos de usuario para una aplicación web. Mi idea actual es almacenar los datos de cada usuario usando la marca de tiempo de cuando se unieron como la clave que hace referencia a los datos de ese usuario. La ventaja de este esquema es que es una forma sencilla de asignar identificadores enteros únicos a los usuarios, y hace que la ordenación cronológica de los usuarios sea simple.

Un inconveniente, sin embargo, es que si se envían dos solicitudes de "agregar usuario" con datos idénticos, la aplicación agregará felizmente dos entradas separadas, que es unideal. Podría barajar las cosas (estoy empezando a pensar que debería usar el correo electrónico como la clave y priorizar mediante la combinación de datos, en lugar de mi esquema actual), pero supongo que no quiero. ¿Hay alguna forma de evitar datos duplicados?

El enfoque ingenuo probablemente sea solo para hacer algo como:

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

Pero esta es definitivamente una condición de carrera; Sería fácil para dos solicitudes consultar y no encontrar ningún usuario en la base de datos, y ambos agregar. Me gustaría hacer esto en una transacción, pero no parece que el soporte de transacciones de Firebase cubra este caso. ¿Hay alguna forma de manejar esto?


Puede utilizar la función de push para generar automáticamente IDs cronológicamente incrementales que no entren en conflicto con otros clientes, incluso si se crean al mismo tiempo (tienen un componente aleatorio en ellos).

Por ejemplo:

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


Probablemente tendrá que usar el nombre de usuario o la dirección de correo electrónico como clave e intentar escribir atómicamente a esa ubicación.

Aquí está el ejemplo de código relevante de la referencia de función de transacción . En este caso, usamos wilma como la clave para el usuario.

// 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/'s data: '', snapshot.val()); });


¿Las reglas de seguridad no son suficientes para hacer cumplir la singularidad? No tengo idea si son atómicos o no.

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


en lugar de definir la regla en la base de datos fire-base, la forma más fácil de evitar entradas duplicadas es obtener todos los datos de la base de datos fire-base y compararlos con los datos (new Data) que desea almacenar, si coinciden con los datos anteriores, descarte el almacenamiento en la base de datos otra vez, almacene en la base de datos. revise a continuación para mayor claridad.

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<>();}

El siguiente código es para agregar datos a la base de fuego

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 para obtener los detalles de la base de datos de firebase

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) { } }); }

finalmente agregue la clase Pojo

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; }

}