0

I'm just starting to learn android studio and I'm working on a location-based project to insert location information into Firebase. I followed tutorial from youtube [https://www.youtube.com/watch?v=CwxdfamaCrk], however in the video only shows insert data from the code which is like this;

infectedArea = new ArrayList<>();
    infectedArea.add(new LatLng(2.2258162, 102.4497224));
    infectedArea.add(new LatLng(2.2252313, 102.4563797));
    infectedArea.add(new LatLng(2.2261818, 102.4551067));
    infectedArea.add(new LatLng(2.275295,102.444035));

    FirebaseDatabase.getInstance()
            .getReference("InfectedArea")
            .child("Location")
            .setValue(infectedArea)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    Toast.makeText(MapsActivity.this, "Updated!", Toast.LENGTH_SHORT).show();
                }
            }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Toast.makeText(MapsActivity.this, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });

Below are the snapshot of my firebase.

enter image description here

The one with index 0, 1, 2 and 3 are inserted from the code. Now I'm trying to continue inserting data from an input form but random key was generated and new geofence cannot be created. Is there anyway to continue inserting data with hard key?

I was thinking on removing the hard key and just use the generated key but then I have no idea how to alter the code to create multiple geofence.

Rhya
  • 47
  • 1
  • 12
  • Firebase intentionally doesn't offer an operation for inserting items with a sequential numeric key. See https://firebase.google.com/docs/database/android/structure-data, https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html and https://stackoverflow.com/questions/39519021/how-to-create-auto-incremented-key-in-firebase – Frank van Puffelen Dec 12 '19 at 22:29

2 Answers2

1

Firebase intentionally doesn't offer an operation for inserting items with a sequential numeric key. See:

That said, you can use array-like structures with sequential numerical indexes, and you can use auto-ids. So let's look at each in turn.


Using sequential numerical indexes

To add a new item with key 4 to your current structure, you will need to:

  1. Determine the highest key
  2. Add a child node with one key higher

In its simplest format, that looks like this (on Android):

FirebaseDatabase.getInstance()
        .getReference("InfectedArea")
        .child("Location")
        .runTransaction(new Transaction.Handler() {
    @Override
    public Transaction.Result doTransaction(MutableData mutableData) {
        String lastKey = "-1";
        for (MutableData child: mutableData.getChildren) {
            lastKey = child.getKey();
        }

        int nextKey = Integer.parseInt(lastKey) + 1;

        mutableData.child("" + nextKey).setValue("your next value here");

        // Set value and report transaction success
        return Transaction.success(mutableData);
    }

    @Override
    public void onComplete(DatabaseError databaseError, boolean b,
                           DataSnapshot dataSnapshot) {
        // Transaction completed
        Log.d(TAG, "Transaction:onComplete:" + databaseError);
    }
});

As you can see that is quite a lot of code. This is largely needed because multiple users may be accessing the same location at almost the same time, and we need to handle this. Firebase uses optimistic locking, but the above may still be come a serious bottleneck when there are multiple users. Plus: this is a lot more complex than your simple push().setValue(...).


Use auto-ids for your initial set of data, and for new data

You can easily write all points with push IDs (those are the keys that push() generates), once you realize that calling only push() doesn't yet write to the database. You can get a new push ID in pure Android code with:

String pushID = ref.push().getKey();

Knowing this, we can change your code to insert the initial locations to:

DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
// It doesn't matter what the reference points to, as push IDs are statistically guaranteed to be unique, independent of their location.

Map<String, Object> values = new HashMap<>();
infectedArea.put(ref.push().getKey(), new LatLng(2.2258162, 102.4497224));
infectedArea.put(ref.push().getKey(), new LatLng(2.2252313, 102.4563797));
infectedArea.put(ref.push().getKey(), new LatLng(2.2261818, 102.4551067));
infectedArea.put(ref.push().getKey(), new LatLng(2.275295,102.444035));

FirebaseDatabase.getInstance()
        .getReference("InfectedArea")
        .child("Location")
        .setValue(values)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                Toast.makeText(MapsActivity.this, "Updated!", Toast.LENGTH_SHORT).show();
            }
        }).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        Toast.makeText(MapsActivity.this, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
    }
});

This will result in a similar structure as you know have, but then with all keys being push IDs.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • your example are showing how to insert the data from code, but what if I want to insert data from input form? – Rhya Dec 13 '19 at 10:55
  • You'd read the data from the code in that case, and construct a map out of it too. But your question was also showing the problem in code, so that's what I answered with. – Frank van Puffelen Dec 13 '19 at 15:20
0

it will stockpile at HashMap, so you can getkey to get random key, and you get random key you can insert data

DatabaseReference database = FirebaseDatabase.getInstance().getReference("InfectedArea").child("Location");
    database_course.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

            for(DataSnapshot ds :dataSnapshot.getChildren()){
               String key = ds.getKey();
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });
Ruyut
  • 151
  • 11