Mahindar Boregam
Mahindar Boregam

Reputation: 855

How to convert a Firestore Document to plain json and vice versa

I'm trying to fetch firestore document using Rest API and it is returning data in below format

{"fields":{"list1":{"arrayValue":{"values":[{"stringValue":"item1"},{"stringValue":"item2"}]}}}}

how can I convert the above Document to plain JavaScript object like below and convert it back to firestore document before making the update call

{"list1":["item1","item2"]}

Screenshot of my data from Firestore console enter image description here

Edit: More info

json sample1 is returned by Firestore api and has all datatype info

json sample2 is my actual data without type info.

My issue is firestore RestApi get call is returning the response in json sample1 format. I want to update some info in api response and send back updated values to firestore db. But due to all the type info in the response I'm not able to update the values where necessary. So I'm trying to find if there is a way to convert api response to json sample2.

API URL used : https://firestore.googleapis.com/v1/projects/projects/{project_id}/databases/{database_id}/documents/{document_path}

Upvotes: 5

Views: 3881

Answers (4)

Konstantin Tarkus
Konstantin Tarkus

Reputation: 38378

How to convert a Firestore document into a normal JSON object:

function toValue(field) {
  return "integerValue" in field
    ? Number(field.integerValue)
    : "doubleValue" in field
    ? Number(field.doubleValue)
    : "arrayValue" in field
    ? field.arrayValue.values.map(toValue)
    : "mapValue" in field
    ? toJSON(field.mapValue)
    : Object.entries(field)[0][1];
}

function toJSON(doc) {
  return Object.fromEntries(
    Object.entries(doc.fields ?? {}).map(([key, field]) => [key, toValue(field)])
  );
}

Upvotes: 1

Mahmoud Moustafa
Mahmoud Moustafa

Reputation: 31

I just want to suggest a minor change to @mahindar's answer to handle 'nullValue', as Firestore recently allowed saving null values. Below is the updated code

let jsonToDocument = function (value) {
    if (!value) {
        return { 'nullValue': null };
    } else if (!isNaN(value)) {
        if (value.toString().indexOf('.') != -1)
            return { 'doubleValue': value };
        else
            return { 'integerValue': value };
    } else if (value === 'true' || value === 'false' || typeof value == 'boolean') {
        return { 'booleanValue': value };
    } else if (Date.parse(value)) {
        return { 'timestampValue': value };
    } else if (typeof value == 'string') {
        return { 'stringValue': value };
    } else if (value && value.constructor === Array) {
        return { 'arrayValue': { values: value.map(v => jsonToDocument(v)) } };
    } else if (typeof value === 'object') {
        let obj = {};
        for (let o in value) {
            obj[o] = jsonToDocument(value[o]);
        }
        return { 'mapValue': { fields: obj } };
    }

}
let documentToJson = function (fields) {
    let result = {};
    for (let f in fields) {
        let key = f, value = fields[f],
            isDocumentType = ['stringValue', 'booleanValue', 'doubleValue',
                'integerValue', 'timestampValue', 'mapValue', 'arrayValue', 'nullValue'].find(t => t === key);
        if (isDocumentType) {
            let item = ['stringValue', 'booleanValue', 'doubleValue', 'integerValue', 'timestampValue', 'nullValue']
                .find(t => t === key)
            if (item)
                return value;
            else if ('mapValue' == key)
                return documentToJson(value.fields || {});
            else if ('arrayValue' == key) {
                let list = value.values;
                return !!list ? list.map(l => documentToJson(l)) : [];
            }
        } else {
            result[key] = documentToJson(value)
        }
    }
    return result;
}
let documentData = { "list1": { "arrayValue": { "values": [{ "stringValue": "item1" }, { "stringValue": "item2" }] } }, "another_value": { "nullValue": null } }
let jsonData = documentToJson(documentData);
let documentData1 = jsonToDocument(jsonData).mapValue.fields;
console.log(JSON.stringify(documentData));
console.log(JSON.stringify(jsonData));
console.log(JSON.stringify(documentData1));

Upvotes: 3

Mahindar Boregam
Mahindar Boregam

Reputation: 855

Seems with rest api only way is to write your own conversion. below code worked out for my requirement

let jsonToDocument = function (value) {
    if (!isNaN(value)) {
        if (value.toString().indexOf('.') != -1)
            return { 'doubleValue': value };
        else
            return { 'integerValue': value };
    } else if (value === 'true' || value === 'false' || typeof value == 'boolean') {
        return { 'booleanValue': value };
    } else if (Date.parse(value)) {
        return { 'timestampValue': value };
    } else if (typeof value == 'string') {
        return { 'stringValue': value };
    } else if (value && value.constructor === Array) {
        return { 'arrayValue': { values: value.map(v => jsonToDocument(v)) } };
    } else if (typeof value === 'object') {
        let obj = {};
        for (let o in value) {
            obj[o] = jsonToDocument(value[o]);
        }
        return { 'mapValue': { fields: obj } };
    }

}
let documentToJson = function (fields) {
    let result = {};
    for (let f in fields) {
        let key = f, value = fields[f],
            isDocumentType = ['stringValue', 'booleanValue', 'doubleValue',
                'integerValue', 'timestampValue', 'mapValue', 'arrayValue'].find(t => t === key);
        if (isDocumentType) {
            let item = ['stringValue', 'booleanValue', 'doubleValue', 'integerValue', 'timestampValue']
                .find(t => t === key)
            if (item)
                return value;
            else if ('mapValue' == key)
                return documentToJson(value.fields || {});
            else if ('arrayValue' == key) {
                let list = value.values;
                return !!list ? list.map(l => documentToJson(l)) : [];
            }
        } else {
            result[key] = documentToJson(value)
        }
    }
    return result;
}
let documentData = { "list1": { "arrayValue": { "values": [{ "stringValue": "item1" }, { "stringValue": "item2" }] } } }
let jsonData = documentToJson(documentData);
let documentData1 = jsonToDocument(jsonData).mapValue.fields;
console.log(JSON.stringify(documentData));
console.log(JSON.stringify(jsonData));
console.log(JSON.stringify(documentData1));

Upvotes: 8

Frank van Puffelen
Frank van Puffelen

Reputation: 598847

To convert this input:

{"fields":{"list1":{"arrayValue":{"values":[{"stringValue":"item1"},{"stringValue":"item2"}]}}}}

To this output:

{"list1":["item1","item2"]}

You can do:

let input = {"fields":{"list1":{"arrayValue":{"values":[{"stringValue":"item1"},{"stringValue":"item2"}]}}}};

let expected = {"list1":["item1","item2"]};

let output = {};
Object.keys(input.fields).forEach((fieldName) => {
  let arrayValue = input.fields[fieldName].arrayValue;
  if (arrayValue) {
    output[fieldName] = arrayValue.values.map((value) => value.stringValue);
  }
});

console.log(output);

Upvotes: 0

Related Questions