8

database structure

Recently I started testing Firebase new document db Firestore for learning purpose, I am stuck right now to access the values store inside the document as object.

I am using the below code to access object Privacy stored in document, but I am not sure how to access the Key - Value? For Example I have 3 sub Key - Value pair in the object, how will I access and edit it individually?

DocumentReference docRef = FirebaseFirestore.getInstance().collection("Users").document("PQ8QUHno6QdPwM89DsVTItrHGWJ3");
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<DocumentSnapshot> task) {
        if (task.isSuccessful()) {
            DocumentSnapshot document = task.getResult();
            if (document != null) {
                Log.d(TAG, "DocumentSnapshot data: " + task.getResult().getData().get("privacy"));
                Object meta_object = task.getResult().getData().get("privacy");
            } else {
                Log.d(TAG, "No such document");
            }
        } else {
            Log.d(TAG, "get failed with ", task.getException());
        }
    }
});

Any help is appreciated, thanks.

Ben Thomas
  • 3,024
  • 2
  • 16
  • 38
Kumar Vivek
  • 321
  • 4
  • 23

1 Answers1

10

The privacy field within your document can be considered a Map<String, Boolean>, so you could cast the value of this field into such a variable:

HashMap<String, Boolean> privacy = (HashMap<String, Boolean>) task.getResult().getData().get("privacy");

Now the main problem with this is that you'll likely see an "unchecked cast" compiler warning because casting a Map like this is not ideal as you can't guarantee that the database structure will always contain String : Boolean values in this field.

In this case, I would suggest using custom objects to store & retrieve objects in your database, which will automatically deal with marshalling and casting for you:

DocumentReference docRef = FirebaseFirestore.getInstance().collection("Users").document("PQ8QUHno6QdPwM89DsVTItrHGWJ3");
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<DocumentSnapshot> task) {
        if (task.isSuccessful()) {
            DocumentSnapshot document = task.getResult();
            if (document != null) {
                User user = task.getResult().toObject(User.class);
            } else {
                Log.d(TAG, "No such document");
            }
        } else {
            Log.d(TAG, "get failed with ", task.getException());
        }
    }
});

Where your User class is something like:

public class User {
    private String username;
    private HashMap<String, Boolean> privacy;

    public User() {}

    public User(String username, HashMap<String, Boolean> privacy) {
        this.username = username;
        this.privacy = privacy;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public HashMap<String, Boolean> getPrivacy() {
        return username;
    }

    public void setPrivacy(HashMap<String, Boolean> privacy) {
        this.privacy = privacy;
    }
}

In this example, the User user = task.getResult().toObject(User.class) call will marshall the entire document into an instance of your User object, and you can then access the privacy map with:

HashMap<String, Boolean> userPrivacy = user.getPrivacy();

Each field in the document will be matched to a field with the same name within your custom object, so you could also add the settings or photo_url fields in the same fashion. You just need to remember:

Each custom class must have a public constructor that takes no arguments. In addition, the class must include a public getter for each property.

Grimthorr
  • 6,246
  • 5
  • 37
  • 51
  • Thanks for the detailed explanation Grimthorr. But how we will handle if the value stored in the object are of different datatypes? Like in privacy some attributes are Boolean while others are String? – Kumar Vivek Dec 15 '17 at 12:09
  • 1
    In that case, you could use `HashMap` for the `privacy` field instead and then cast each item manually when required, something like: `(Boolean) privacy.get("friends_challenge")`. – Grimthorr Dec 15 '17 at 12:33