Cómo comprobar que ciertos datos ya existen en Firestore o no

Resuelto Ragavendra vignesh asked hace 54 años • 1 respuestas

Antes de agregar nuevos datos al Firestore, quiero verificar que ya existan datos del mismo tipo en la base de datos o no. Si ya había datos presentes, quiero evitar que el usuario ingrese datos duplicados en la base de datos. En mi caso, es como una reserva de cita si ya existe una reserva para el mismo tiempo, quiero evitar que los usuarios reserven al mismo tiempo. Intenté usar la función de consulta pero no impide la entrada de datos duplicados. Alguien por favor ayúdeme

private boolean alreadyBooked(final String boname, final String bodept, final String botime) {
        final int[] flag = {0};
        CollectionReference cref=db.collection("bookingdetails");
        Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
        q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
            @Override
            public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                for (DocumentSnapshot ds : queryDocumentSnapshots) {
                    String rname, rdept, rtime;
                    rname = ds.getString("name");
                    rdept = ds.getString("dept");
                    rtime = ds.getString("time");
                    if (rdept.equals(botime)) {
                        if (rtime.equals(botime)) {
                            flag[0] = 1;
                            return;
                        }
                    }
                }
            }
        });
        if(flag[0]==1){
            return true;
        }
        else {
            return false;
        }
    }
Ragavendra vignesh avatar Jan 01 '70 08:01 Ragavendra vignesh
Aceptado

La carga de datos desde Cloud Firestore se realiza de forma asincrónica. Cuando regresa de alreadyBooked, los datos aún no se han cargado, onSuccessno se han ejecutado aún y flagtodavía tienen su valor predeterminado.

La forma más sencilla de ver esto es con algunas declaraciones de registro:

private boolean alreadyBooked(final String boname, final String bodept, final String botime) {
    CollectionReference cref=db.collection("bookingdetails");
    Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
    System.out.println("Starting listener");
    q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
            System.out.println("Got data from Firestore");
        }
    });
    System.out.println("Returning");
}

Si ejecuta este código se imprimirá:

Oyente inicial

Regresando

Obtuve datos de Firestore

Probablemente ese no sea el orden que esperaba. Pero explica perfectamente por qué siempre recibes falsellamadas cuando llamas alreadyBooked: los datos simplemente no regresaron de Firestore a tiempo.

La solución para esto es cambiar su forma de pensar sobre el problema. Su código actual tiene lógica: "Primero verifique si ya está reservado, luego agregue un nuevo artículo". Necesitamos replantear esto como: "Comience a verificar si ya está reservado. Una vez que sepamos que no lo está, agregue un nuevo artículo". En código, esto significa que todo el código que necesita datos de Firestore debe estar dentro de onSuccesso debe llamarse desde allí.

La versión más sencilla es mover el código a onSuccess :

private void alreadyBooked(final String boname, final String bodept, final String botime) {
    CollectionReference cref=db.collection("bookingdetails");
    Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
    q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
            boolean isExisting = false
            for (DocumentSnapshot ds : queryDocumentSnapshots) {
                String rname, rdept, rtime;
                rname = ds.getString("name");
                rdept = ds.getString("dept");
                rtime = ds.getString("time");
                if (rdept.equals(botime)) {
                    if (rtime.equals(botime)) {
                        isExisting = true;
                    }
                }
            }
            if (!isExisting) {
                // TODO: add item to Firestore
            }
        }
    });
}

Si bien esto es simple, lo hace alreadyBookedmenos reutilizable ya que ahora también contiene el código para insertar el nuevo elemento. Puedes resolver esto definiendo tu propia interfaz de devolución de llamada:

public interface AlreadyBookedCallback {
  void onCallback(boolean isAlreadyBooked);
}

private void alreadyBooked(final String boname, final String bodept, final String botime, AlreadyBookedCallback callback) {
    CollectionReference cref=db.collection("bookingdetails");
    Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
    q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
            for (DocumentSnapshot ds : queryDocumentSnapshots) {
                String rname, rdept, rtime;
                rname = ds.getString("name");
                rdept = ds.getString("dept");
                rtime = ds.getString("time");
                if (rdept.equals(botime)) {
                    if (rtime.equals(botime)) {
                        isExisting = true;
                    }
                }
            }
            callback.onCallback(isExisting)
        }
    });
}

Y luego lo llamas como:

alreadyBooked(boname, bodept, botime, new AlreadyBookedCallback() {
  @Override
  public void onCallback(boolean isAlreadyBooked) {
    // TODO: insert item
  }
});

Consulte también (muchos de estos son para Firebase Realtime Database, donde se aplica la misma lógica):

  • El método getContactsFromFirebase() devuelve una lista vacía
  • Publicación del blog de Doug sobre devoluciones de llamadas asincrónicas
  • Establecer el valor de la propiedad Singleton en Firebase Listener
  • Android + Firebase: sincrónico para una función asincrónica
  • ¿Es posible cargar datos sincrónicamente desde Firebase?
  • Consultando datos desde firebase
Frank van Puffelen avatar Jun 23 '2018 15:06 Frank van Puffelen