The Employee 123
The Employee 123

Reputation: 504

Android - Firebase - Retrieving Data from Node X and Sending it to Node Y

Aim

Allow Users to send reports to the authorities. Reports will be stored and will not be overwritten when new Reports are entered by the same user

Picture of Current Database

enter image description here

The current user signed in is able to store "Incident Report" into the Database but apparently when the user submits another "Incident Report", the newly submitted "Incident Report" will overwrite the data of the previous "Incident Report"

Picture of Desired Database

enter image description here

The Yellow Highlighted data is supposed to be data retrieved from the "Users" child "name" which is the Red Circled data

For example, if the data within the Red Circled data is "Abe Long", the data of the Yellow Highlighted will be "Abe Long" as well.

In addition to that, when the current signed in User submits an "Incident Report", each new one created will create a new Unique Key. This means it will not overwrite the previously submitted data.

Report Fragment Class

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

import java.util.Date;
import java.util.HashMap;


public class ReportFragment extends Fragment {

    private EditText jReportDatePick;
    private EditText jReportTimeEnt;
    private EditText jReportLocationEnt;
    private EditText jReportDescriptionEnt;

    private Button jReportSendBtn;

    private FirebaseUser jReportCurrentUserID;

    private DatabaseReference jReportByUserDatabase;

    private ProgressDialog jReportLoad;

    public ReportFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View viewRoot = inflater.inflate(R.layout.fragment_report, container, false);

        jReportDatePick = viewRoot.findViewById(R.id.reportDatePick);
        jReportTimeEnt = viewRoot.findViewById(R.id.reportTimeEnt);
        jReportLocationEnt = viewRoot.findViewById(R.id.reportLocationEnt);
        jReportDescriptionEnt = viewRoot.findViewById(R.id.reportDescriptionEnt);

        jReportSendBtn = viewRoot.findViewById(R.id.reportSendBtn);

        jReportLoad = new ProgressDialog(getActivity());

        jReportSendBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String userReportDate = jReportDatePick.getText().toString();
                String userReportTime = jReportTimeEnt.getText().toString();
                String userReportLocation = jReportLocationEnt.getText().toString();
                String userReportDescription = jReportDescriptionEnt.getText().toString();

                if(!TextUtils.isEmpty(userReportDate)&&
                        !TextUtils.isEmpty(userReportTime)&&
                        !TextUtils.isEmpty(userReportLocation)&&
                        !TextUtils.isEmpty(userReportDescription)){
                    submitReport(userReportDate, userReportTime, userReportLocation, userReportDescription);
                    jReportLoad.setTitle("Sending Report");
                    jReportLoad.setMessage("Please wait while the report is being sent");
                    jReportLoad.setCanceledOnTouchOutside(false);
                    jReportLoad.show();
                }else{
                    jReportLoad.dismiss();
                    Toast.makeText(getActivity(), "Report failed to be sent due to empty inputs", Toast.LENGTH_SHORT).show();
                }

            }
        });

        return  viewRoot;
    }

    private void submitReport(final String userReportDate,final String userReportTime,
                              final String userReportLocation,final String userReportDescription) {

        jReportCurrentUserID = FirebaseAuth.getInstance().getCurrentUser();
        final String reportUserID = jReportCurrentUserID.getUid();
        jReportByUserDatabase = FirebaseDatabase.getInstance().getReference().child("Incident Reports").child(reportUserID);

        HashMap<String, String> incidentReportUser = new HashMap<>();
        incidentReportUser.put("date", userReportDate);
        incidentReportUser.put("time", userReportTime);
        incidentReportUser.put("location", userReportLocation);
        incidentReportUser.put("description", userReportDescription);

        jReportByUserDatabase.setValue(incidentReportUser).addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if(task.isSuccessful()){
                    jReportLoad.dismiss();
                    Toast.makeText(getActivity(), "Report was Sent", Toast.LENGTH_SHORT).show();
                    jReportDatePick.setText("");
                    jReportTimeEnt.setText("");
                    jReportLocationEnt.setText("");
                    jReportDescriptionEnt.setText("");
                }else{
                    jReportLoad.dismiss();
                    Toast.makeText(getActivity(), "Report failed to be sent", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

Additional Comments

I do not intend for the currently signed in User to be able to submit their name, that will create a possibility of the User entering someone else's name into the "Incident Report". I intend for the "CurrentUser signed in" name to be retrieved and entered into the "Incident Report" automatically.

Instead of putting jReportByUserDatabase.setValue(incidentReportUser) I have tried putting .updateChildren while using Map<String, Object>. The problem was that each data was not entered under a "Unique ID" which will be stored under "Incident Report" within the Data Tree


Solution to the Problem

Helped by both Cadet and JavaBanana

Implementing a "For Loop DataSnapshot" to loop through the data and retrieving the desired one by also using the "Users class" which contains the name, address, status, etc.

private void submitReport(final String userReportDate,final String userReportTime,
                          final String userReportLocation,final String userReportDescription) {

DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();
dbRef.child("Users").addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
            Users user = snapshot.getValue(Users.class);
            HashMap<String, String> incidentReportUser = new HashMap<>();
            incidentReportUser.put("name", user.name);
            incidentReportUser.put("date", userReportDate);
            incidentReportUser.put("time", userReportTime);
            incidentReportUser.put("location", userReportLocation);
            incidentReportUser.put("description", userReportDescription);

            jReportCurrentUserID = FirebaseAuth.getInstance().getCurrentUser();
            final String reportUserID = jReportCurrentUserID.getUid();
            jReportByUserDatabase = FirebaseDatabase.getInstance().getReference().child("Incident Reports").child(reportUserID);
            jReportByUserDatabase.push().setValue(incidentReportUser).addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if(task.isSuccessful()){
                        jReportLoad.dismiss();
                        Toast.makeText(getActivity(), "Report was Sent", Toast.LENGTH_SHORT).show();
                        jReportDatePick.setText("");
                        jReportTimeEnt.setText("");
                        jReportLocationEnt.setText("");
                        jReportDescriptionEnt.setText("");
                    }else{
                        jReportLoad.dismiss();
                        Toast.makeText(getActivity(), "Report failed to be sent", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
    }
});
}

Upvotes: 1

Views: 228

Answers (2)

Cadet
Cadet

Reputation: 366

Write it by this way (Push adds values, instead of overriding).

jReportByUserDatabase.push()setValue(incidentReportUser)

Also, I recommend to make the Report node containing the user fields also. Like combine them to flat node.

enter image description here

Upvotes: 2

rsanath
rsanath

Reputation: 1210

Okay so the main problem with your designs that you are storing the reports under the user's Id which firebase will overwrite obviously.

You can generate a random key for storing your reports and set your report at the generated key in the database.

public class Report {
  String reportId; // This is important
  String reporterId;  //This is important
  String reporterName;
  String userType;
  String status;
  String address;
  String neibourhood;
  String image;
}

DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("Incident Reports");
String reportId = dbRef.push().getKey(); //This generates a new key and returns it
Report report = new Report("report id", "reporter id", "other stuff"... "etc");
dbRef.child(reportId).setValue(report);

To Retrieve the names of the Users

DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();
dbRef.child("Users").addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        //Loop through the retrieved user data
        for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
            User user = snapshot.getValue(User.class);
            System.out.println(user.name);
        }
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {}
});

Upvotes: 1

Related Questions