Canato
Canato

Reputation: 3968

Get JSON Object from Google Cloud Firestore

This was the closest question that I found but still not what I'm looking for.

I'm using google Firestore to save user information (number, sex, etc). I use a JSON custom object to save, but when I'm trying to get the information I'm not able to transform in JSON object again.

private void getUserData() {
  ffDatabase.collection(Objects.requireNonNull(mAuth.getCurrentUser()).getUid()).get()
   .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
     @Override
     public void onComplete(@NonNull Task<QuerySnapshot> task) {
       if (task.isSuccessful()) {                 
         JSONObject user = new JSONObject(task.getResult()
                                         .toObjects(JSONObject.class).get(0));
         DataStorageTemporary.getInstance().setJsonUser(user);
       } else {
         Log.w("ERROR load data", "Error getting documents.", task.getException());
       }
     }
  });
}

I tried to get from Task(result) the JSON object, but it won't work:

I know that I can change QuerySnapshot to DocumentSnapshot, but I still no able to get the JSON Object from.

Upvotes: 2

Views: 10083

Answers (4)

Arie Laxed
Arie Laxed

Reputation: 123

I took @atmandhol's solution as a starting point but used the JsonObjectBuilder. I also converted the chars-string-valueType structure of Firestore back to a single JsonStructure.

Use it as inspiration (not a full-proof solution). E.g. more valueTypes than "STRING" need to be added.

    private JsonObject mapToJSON(Map<String, Object> map) {

    JsonObjectBuilder builder = Json.createObjectBuilder();

    for (Map.Entry<String, Object> entry : map.entrySet()) {
        String key = entry.getKey();
        Object value = entry.getValue();
        if ( isSingleElement(value) ) {
            builder.add(key, getSingleValueAsString(((Map) value)));

        } else if (value instanceof Map) {
            Map<String, Object> subMap = (Map<String, Object>) value;
            builder.add(key, mapToJSON(subMap));
        } else if (value instanceof List) {
            builder.add(key, listToJSONArray((List<Object>) value));
        }
        else {
            builder.add(key, value.toString());
        }
    }
    return builder.build();
}

private String getSingleValueAsString(Map value) {
    if( value.get("valueType").equals("STRING") ) {
        return value.get("string").toString();
    }
    return "";
}

private boolean isSingleElement(Object value) {
    return ( value instanceof Map
            && ((Map) value).containsKey("valueType"));
}

private JsonArray listToJSONArray(List<Object> list) {
    JsonArrayBuilder builder = Json.createArrayBuilder();

    for(Object value: list) {
        if ( isSingleElement(value) ) {
            builder.add(getSingleValueAsString(((Map) value)));

        } else if (value instanceof Map) {
            builder.add(mapToJSON((Map<String, Object>) value));
        }
        else if(value instanceof List) {
            builder.add(listToJSONArray((List<Object>) value));
        }
        else {
            builder.add(value.toString());
        }
    }
    return builder.build();
}

Upvotes: 1

atmandhol
atmandhol

Reputation: 11

ApiFuture<QuerySnapshot> future = db.collection(collection).get();
List<QueryDocumentSnapshot> documents = future.get().getDocuments();

Iterate through the DocumentSnapshots and use recursion to create a JSONObject. You can use getData() on DocumentSnapshot object to get a Map of your Firestore Document and then you can parse the object and create your own JSONObject.

for (DocumentSnapshot document : documents) {

JSONObject obj = mapToJSON(document.getData());

// Other stuff here ...
}

private JSONObject mapToJSON(Map<String, Object> map) {
        JSONObject obj = new JSONObject();

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof Map) {
                Map<String, Object> subMap = (Map<String, Object>) value;
                obj.put(key, mapToJSON(subMap));
            } else if (value instanceof List) {
                obj.put(key, listToJSONArray((List) value));
            }
            else {
                obj.put(key, value);
            }
        }
        return obj;
    }

    private JSONArray listToJSONArray(List<Object> list) {
        JSONArray arr = new JSONArray();
        for(Object obj: list) {
            if (obj instanceof Map) {
                arr.add(mapToJSON((Map) obj));
            }
            else if(obj instanceof List) {
                arr.add(listToJSONArray((List) obj));
            }
            else {
                arr.add(obj);
            }
        }
        return arr;
    }

Upvotes: 1

ZeusLawyer
ZeusLawyer

Reputation: 294

You would need to create a custom User Class and then write to firestore using that POJO as @Doug Stevenson says. see the following from the docs:

"Custom objects Using Java Map objects to represent your documents is often not very convenient, so Cloud Firestore also supports writing your own Java objects with custom classes. Cloud Firestore will internally convert the objects to supported data types."

Upvotes: 2

Doug Stevenson
Doug Stevenson

Reputation: 317352

Firestore doesn't store JSON. It stores key/value pairs with strongly typed values. When you read a document on Android, you have two choices to get a hold of those fields:

  1. Automatically map the key/value pairs to a POJO that conforms to JavaBeans standards. JSONObject is not a valid JavaBean type object.
  2. Access each key/value pair out of the document individually.

Upvotes: 2

Related Questions