Kevin
Kevin

Reputation: 59

Firestore retrieve nested object and convert to POJO

I have nested objects in Firestore where I have the document tied to the logged in user's UUID.

I am able to get the nested values out by converting to a Map and calling getData on the DocumentSnapshot. Then looping over the Map entry set. I have typically used Firestore's methods to convert the result back over to my custom object (e.g. documentSnapshot.toObject(POJO.class) and throw them in a list, but since I am getting the nested values as a Map, will I need to use something like Jackson or GSON? Once this loop is done, I want to convert to POJO and add each to the arraylist, in this case allVehices.

public ArrayList<Vehicle> getAllVehicles() {
    FirebaseFirestore.getInstance().collection("vehicles")
            //.whereEqualTo("vehicleUUID",FirebaseAuth.getInstance().getCurrentUser().getUid())
            .get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {
                    if (task.isSuccessful()) {
                        for (DocumentSnapshot documentSnapshot : task.getResult()) {
                            Map<String,Object> map = (Map<String,Object>) documentSnapshot.getData();
                            for (Map.Entry<String,Object> entry : map.entrySet()) {
                                System.out.print(entry.getKey() + "/" + entry.getValue());

                            }
                        }
                    }
                }
            });

    return allVehicles;

}

Firestore structure

Upvotes: 3

Views: 1715

Answers (3)

colithium
colithium

Reputation: 10327

It appears this feature was added in version 18.0.0 which released shortly before this question was asked. The Firestore Android API supports mapping nested object fields to and from their respective classes.

Parent.java

public class Parent {
  private Child child;

  public Parent() {
    this(null);
  }

  public Parent(Child child) {
    this.child = child;
  }

  public Child getChild() {
    return child;
  }
}

Child.java

public class Child {
  private String value;

  public Child () {
    this(null);
  }

  public Parent(String value) {
    this.value = value;
  }

  public String getValue() {
    return value;
  }
}

Repository.java

// Store Parent:
firestore.collection("collection")
    .document("id1")
    .set(myParent);  // Add appropriate listeners
// Retrieve Parent:
client.collection("collection")
    .document("id1")
    .get()
    // The returned Parent instance will have the child field set.
    .addOnSuccessListener(snapshot -> snapshot.toObject(Parent.class);

Upvotes: 0

Thomas Burke
Thomas Burke

Reputation: 1375

GSON can work as a workaround for documents that contain maps that you would like to have each as their own individual object. So if your mapping individual fields into Java objects the below code is a workaround for SDK limitations, but will have worse performance than the SDK or Jackson.

public ArrayList<Vehicle> getAllVehicles() {
    FirebaseFirestore.getInstance().collection("vehicles")
            //.whereEqualTo("vehicleUUID",FirebaseAuth.getInstance().getCurrentUser().getUid())
            .get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {
                    if (task.isSuccessful()) {
                        for (DocumentSnapshot documentSnapshot : task.getResult()) {
                            Map<String,Object> map = (Map<String,Object>) documentSnapshot.getData();
                            for (Map.Entry<String,Object> entry : map.entrySet()) { 
                                Gson gson = new Gson();
                                JsonElement jsonElement = gson.toJsonTree(entry.getValue());
                                MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);
                                pojo.setKeyName(entry.getKey());

                            }
                        }
                    }
                }
            });

    return allVehicles;

}

Upvotes: 1

Doug Stevenson
Doug Stevenson

Reputation: 317760

Yes, you will have to find your own solution to this one, as the Firestore SDK doesn't currently support mapping individual fields into Java objects. It only works with the entire contents of the document right now.

Feel free to file a feature request if you would like the SDK to provide a way to do this mapping for you.

Upvotes: 1

Related Questions