Firebase: Adding Nodes With child: v. childByAutoId

As a new iOS developer, my end goal is to write full-stack code. Until then, Firebase is unbelievably useful as a Back End As A Service. Overall I think their documentation and guides are excellent. However, I did discover something about adding child nodes that I didn’t explicitly understand from their guide on “Saving Data”. I think what I learned can be helpful to any future first-time Firebase-ers. We’ll talk about two methods: childByAutoId and child:. I’ll use creating and adding a user as the example.


First, they give this suggestion for adding a user: (We’ll break it down later)

[[[_ref child:@"users"] child:user.uid]
setValue:@{@"username": username}];

Separately, to append nodes to a list of data, they recommend using childByAutoId. This method, called on an existing reference (Class: FIRDatabaseReference), returns another reference with it’s key being a randomly generated string, and the value whatever you pass as the argument in the setValue method.

That would look like this:

FIRDatabaseReference *newReference= [existingReference childByAutoId];
[newReference setValue:@{@"key" : value}];

The main purpose of childByAutoId is to allow multiple users to add multiple children to a node, without causing any problems in overlap. For example, two different users can both post the same book for rent, at the same time.

Here’s an example of what that would look like. The key to the dictionary is the randomly generated string, beginning with “-KOkGD…”, and the value is another dictionary:

"-KOkGD9n-ysFqX2DtyKp" =     {
latitude = "40.707603";
longitude = "-73.941470";
owner = maXOnUzXy1WpGZMAWzK7sQDg3NH2;
};

The questions I was left with were: “How do I create new children of a node without using childByAutoId, so that I can control what the key is?” For example, how can I save a user with their key being an email or User ID instead of a randomly generated string? How can I name a new parent node in a database? The answer was right at the beginning of their guide: It’s the “child:” method!

This is what threw me off: The documentation says that “child:” ‘Gets a FIRDatabaseReference for the location at the specified relative path.’ Then, says that “childByAutoId” ‘generates a new child location using a unique key and returns a FIRDatabaseReference to it.’ Again, this is also their primary suggestion for adding a user. I was left thinking that the only way to ‘generate a new child location’ was to use childByAutoId, and the only way to reference existing children was child:. But, we can also generate and name new child locations with the child: method. Let’s revisit and rewrite the first code snippet to more explicitly show what this method does. (It’s important to point out that child: takes an NSString, which is the path name, as it’s argument)

With that, here’s another way to add a user: (This all gets called inside the createUserWithEmail: password: completion: method)

// This dictionary will be the passed value in 'setValue'.
NSDictionary *userInformation = @{@"email" : email};
// This is the root reference of the database.
FIRDatabaseReference *rootReference = [[FIRDatabase database] reference];
// This creates a new child location under the root reference, that // will be called "users". 
FIRDatabaseReference *usersReference = [rootReference child:@"users"];
// This creates a new child location under the "users" reference,
// that will be the user's UID.
FIRDatabaseReference *newUserReference = [usersReference child:user.uid];
// This sets the value of the dictionary for which UID is the key. 
// We created this on the first line.
[newUserReference setValue:userInformation];

After adding a user, the node would look like this:

"rootReference" =     {
"users" =
"maXOnUzXy1WpGZMAWzK7sQDg3NH2 =
"email" = "email@domain.com";
};

This, to me, is the most crucial point when using the child: method:

If there is an existing node with the name that you pass in as the argument, they method will return a reference to that node. If there isn’t, the method will return a reference to a new node named with the argument that you passed.

Knowing the difference between childByAutoId: and child: has helped me specifically structure, flatten, name, and edit a database. Where childByAutoId is used to add to a list of items, child: is useful for two things: Controlling the name and values of new nodes, and creating references to pre-existing nodes.

If this has been helpful at all, recommend this article and let me know! Thanks!