How to set foreign keys in Firestore?

in order to query all the items posted by a specific user.

To achieve this, there is no need to set user_id as a foreign key in each items posted as well as item_id in users collection. You can only add a new property to the item object named postedBy which will hold as a value the user id. To display only the items of a specific user you need to query the database using the following code:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference itemsRef = rootRef.collection("items");
Query query = itemsRef.whereEqualTo("postedBy", user_id);

There is also another approach in which involves duplicating data. There is no problem with this tehnique, when it comes to Firebase. This is a quite common practice, which is named denormalization and for that, I recommend you see this video, Denormalization is normal with the Firebase Database. This is for Firebase Realtime database but the concept applies in the same way also to Cloud Firestore.

So with other words, you can create a new collection in which you can store all items that were added by a specific user. The database structure should look like this:

Firestore-root
     |
     --- users (collecton)
          |
          --- userId (document)
                 |
                 --- userItems (collecton)
                        |
                        --- itemId (document)

When you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.


If you want to have a reference to another table with a foreign key, you should store for example the user id with the data you want to work, for example, let's say you have this structure

enter image description here

This is from my project, I have for example a node that is likes, each like is a push key, and inside that pushkey I have the userID of each user who liked a post, the post is represented with the pushKey

Now, I have another node that is called users, and inside you can see my userID

enter image description here

As you can see, I have the same userID in my node users that is in my likes node.

So what I'd do is this

  • I store all the data in users (with the userID as the main node pk)
  • When I like a post I request the userID of that user who liked , pull it up and store it in my Likes node.

This is how I use a foreign key like the userID to work with 2 different nodes

Now, let's say I want to brinf up all the likes from one photo, I just loop through my likes node and each push key is a photo, so I do the same process and get all the photos and likes of each one. So if I get all the likes of the photos I'm also getting the userID who liked, because it's inside my likes node, and then with that I can just reach to the users node and get all the data from the user who liked.

PS: there is not special methods or something to create foreign keys, it depends on your structure and how you will build your app. You set your fk by yourself thinking on how to merge two tables and use the info from both, in this case two nodes that interact with each other.


Let's say you have a shop item in shop/{shop_id} as a document, which has a reference field pointing to user/{user_id}. To set this reference programmatically:

FirebaseFirestore firestore = FirebaseFirestore.getInstance();
DocumentReference userRef = firestore.collection("user").document({user_id});
Map<String, Object> map = new HashMap<>();
map.put("user", userRef);
firestore.collection("shop").document({shop_id}).update(map);

To retrieve that user, you can do:

firestore.collection("shop").document({shop_id}).addSnapshotListener(this, (shopItemSnapshot, e) -> {
    // Get the shopItem here
    // ShopItem shopItem = shopItemSnapshot.toObject(ShopItem.class);
    ((DocumentReference) shopItemSnapshot.get("user")).addSnapshotListener((userSnapshot, e1) -> 
        // Get the user from the shopItem document
        User user = userSnapshot.toObject(User.class);
    });
});