Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add an item to a list in Firebase Database

I have the following Firebase database structure. uIds is a type of List<String>. I am trying to add another uId under uIds with an incremented index. setValue() and updateChildren() would require me to retrieve existing data, and push() will add an item with a randomly generated string as a key instead of an incremented index. Is there a simpler way that does not require to retrieve the existing data? Thanks!

  "requests" : {
    "request001" : {
      "interests" : [ "x" ],
      "live" : true,
      "uIds" : [ "user1" ]  // <---- from this
    },
    "request002" : {
      "interests" : [ "y" ],
      "live" : true,
      "uIds" : [ "user2" ]
    }
  }

--------------------------------

Edit:

Sorry for the unclarity. Let me elaborate to make it clear. Say I have the above database and want to update it to the following.

  "requests" : {
    "-KSVYZwUQPfyosiyRVdr" : {
      "interests" : [ "x" ],
      "live" : true,
      "uIds" : [ "user1", "user2" ]   // <--- to this
    },
    "-KSl1L60g0tW5voyv0VU" : {
      "interests" : [ "y" ],
      "live" : true,
      "uIds" : [ "user2" ]
    }
  }

ishmaelMakitla's suggestion, mDatabase.child("requests").child("request001").setValue(newRequest), will overwrite the "request001" with "newRequest". So I should retrieve the existing data of "request001" and add "user2" to the list uIds. It will be something like this:

mDatabase.child("requests").child("request001").addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        Request newRequest = dataSnapshot.getValue(Request.class);
        newRequest.uIds.add("user2");
        mDatabase.child("requests").child("request001").setValue(newRequest);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}

});

But I am wondering if this process is necessary since what I am trying to do is simply to add one item to the list uIds.

like image 297
Megool Avatar asked Oct 02 '16 08:10

Megool


People also ask

Can Firebase store list?

Cloud Storage for Firebase allows you to list the contents of your Cloud Storage bucket. The SDKs return both the items and the prefixes of objects under the current Cloud Storage reference. Projects that use the List API require Cloud Storage for Firebase Rules Version 2.

What is orderByChild in Firebase?

Inherited from Query.orderByChild. Generates a new Query object ordered by the specified child key. Queries can only order by one key at a time. Calling orderByChild() multiple times on the same query is an error. Firebase queries allow you to order your data by any child key on the fly.


2 Answers

The Firebase documentation on creating data that scales proposes that you use a different data structure:

"requests" : {
  "-KSVYZwUQPfyosiyRVdr" : {
    "interests" : { "x": true },
    "live" : true,
    "uIds" : { 
      "user1": true, 
      "user2": true 
    }
  },
  "-KSl1L60g0tW5voyv0VU" : {
    "interests" : { "y": true },
    "live" : true,
    "uIds" : { 
      "user2": true 
    }
  }
}

Here are a few of the reasons why this data structure works better:

  • each uid can now automatically only appear once. We've essentially modeled our data as a set, instead of using an array.
  • adding an item is now as easy as ref.child("uUids").child("user3").setValue(true)
  • you can now check if a uid exists in your security rules.

I have started re-iterating to myself: whenever you find yourself doing array.contains("xyz"), you should probably be using a set instead of an array. The above mapping with "key": true is an implementation of a set on Firebase.

Efficiency

Some people may think arrays are a more efficient way of storing the data, but in the case of Firebase that is not true:

What you see:

"uIds" : [ "user1", "user2" ]

What Firebase stores:

"uIds" : {
  "0": "user1",
  "1": "user2"
}

So storing a set is pretty much the same:

"uIds" : { 
  "user1": true, 
  "user2": true 
}
like image 147
Frank van Puffelen Avatar answered Oct 20 '22 08:10

Frank van Puffelen


Not sure what you mean when you say setValue, etc require you to retrieve existing data. The basic flow for inserting new record is as follows:

private DatabaseReference mDatabase;
// get reference to your Firebase Database.
mDatabase = FirebaseDatabase.getInstance().getReference();
//and here you add a new child to your 'requests' collection
//I am assuming you have a Request model like this..
Request newRequest = new Request(some-params);
mDatabase.child("requests").child(someRequestId).setValue(newRequest);

You can take a look at basic usage guide for Saving Data on Android Firebase.

Update: Following your comment - I think what you are looking to do can be achieved like this: You use the push() method which generates a unique ID every time a new child is added to the specified Firebase reference:

Firebase newRequestRef = mDatabase.child("request").push();
newRequestRef.setValue(newRequest);

This should do it.

I hope this helps.

like image 45
ishmaelMakitla Avatar answered Oct 20 '22 08:10

ishmaelMakitla