Skip to content
Advertisement

Firebase Realtime Database, only send data if the key && date don’t exists

I have done a lot of research and read through multiple stackoverflow questionso on firebase. Some were kind of helpful. But none that particularly helped my problem. I am trying to make a menu planner. There for I need more than one check to test if for example. Date exists, serviceType is === to “lunch” || “dinner”.

I have a function that adds and image saves url and input data to a state in react. I then use, useEffect to listen for the state update and send the data to firebase. I only want to send new data to firebase IF all the checks pass and they don’t exists. Other wise I want to update my data. I have tried. Foreach, for in, ref(‘link/’+ localState.id). Many different methods that I can’t seem to get right.

This is the form Submit function:

const handleSubmit = (e) => {
    e.preventDefault();

    if (image) {
      const uploadTask = storage.ref(`images/${image.name}`).put(image);

      uploadTask.on(
        "state_changed",
        (snapshot) => {
          const progress = Math.round(
            (snapshot.bytesTransferred / snapshot.totalBytes) * 100
          );

          setProgress(progress);
        },
        (error) => {
          setError(error);
        },
        () => {
          storage
            .ref("images")
            .child(image.name)
            .getDownloadURL()
            .then((url) => {
              const value = state.serviceType;
              const keys = Object.keys(value);
              var filtered = keys.filter(function (key) {
                return value[key];
              });

/////////I have also tried this method, to use one function for all instead of using useEffect//////

              const mealData = db().ref().child("meals");
              const newMealdata = mealData.push();
              //  newMealdata.set({
              //    serviceId: newMealdata.key,
              //    date: props.dates,
              //    serviceType: filtered,
              //    service: {
              //      mealService: state,
              //      image: url,
              //    },
              //  });
///////////////////////////////////////////////

              setNewState((prev) => {
                return {
                  ...newState,
                  date: props.dates,
                  serviceType: filtered,
                  serviceId: newMealdata.key,
                  service: state,
                };
              });

              setProgress(0);
            });
        }
      );
    } else {
      setError("Error Please Choose an Image to Upload");
    }
  };

useEffect function

 useEffect(() => {
    console.log("newState mounterd: ", newState);
    db()
      .ref("meals/" + newState.serviceId)
      .set({ newState });
  }, [newState]);

I have tried using the state.id to check if it equals to the snapshot.key and although they do check. firebase still creates a new node of data with the same date, but with different Ids and the data I want to update instead.

So how would it be best to say:

if(snapshot.val().date === props.dates && snapshot.val().serviceId === snapshot.key && servicetype === "lunch" || 'dinner'){
update({with new inserted data})
}else if(data doesn't match){
ref('meals').set({createNewNode})
}

Advertisement

Answer

The Firebase databases implement fairly limited query support. To expand that you often have to:

  1. Expand/modify your data model to allow the query you want
  2. Do part of your filtering in either client-side code, or in other systems (such as a dedicated full-text search engine).

There is no way to implement your conditions in a query on the Realtime Database, since:

  • It only supports a single condition per query.
  • It doesn’t support OR conditions.

You can sometimes combine multiple AND conditions into a single query, by adding a synthetic property to your data, such as "dates_serviceId": "..._...". With such a property in place, you can then query for ref.orderBy("dates_serviceId").equalTo("myDate_myServiceId").

To be able to query on nodes that have either lunch or dinner service, you’d have to expand your data model to explicitly identify such nodes, for example by adding a "lunch_or_dinner": true property to them. With such a node, you can then query: ref.orderBy("lunch_or_dinner").equalTo(true)

By combining these two approaches, you could even create a single property for the entire query (dates_serviceId_lunch-or-dinner), although I must admit that is becoming a bit overly specific even to my taste.

Advertisement