There is a small limitation with the code provided by @sfdcfox and @salesforce-sas. It works fine for non-relationship fields, however, once you start accessing a related record's values from the current object; it stops working.
const data = {
"apiName":"Case",
"childRelationships":{},
"id":"500R000000AbnzLIAR",
"lastModifiedById":"00541000008D4ZxAAK",
"lastModifiedDate":"2020-03-07T05:53:12.000Z",
"recordTypeId":"01241000001AT6fAAG",
"recordTypeInfo":{
"available":true,
"defaultRecordTypeMapping":true,
"master":false,
"name":"CAG Cases",
"recordTypeId":"01241000001AT6fAAG"
},
"systemModstamp":"2020-03-07T05:53:12.000Z",
"fields":{
"Account":{
"displayValue":"Bob the Builder",
"value":{
"apiName":"Account",
"childRelationships":{},
"id":"001R000001QN4GRIA1",
"lastModifiedById":"00541000008D4ZxAAK",
"lastModifiedDate":"2020-03-07T04:25:36.000Z",
"recordTypeId":"012410000012ujhAAA",
"recordTypeInfo":{
"available":true,
"defaultRecordTypeMapping":false,
"master":false,
"name":"Billing",
"recordTypeId":"012410000012ujhAAA"
},
"systemModstamp":"2020-03-07T04:25:36.000Z",
"fields":{
"Name":{
"displayValue":null,
"value":"Bob the Builder"
}
}
}
},
"AccountId":{
"displayValue":null,
"value":"001R000001QN4GRIA1"
},
"Handle__c":{
"displayValue":null,
"value":null
},
"Origin":{
"displayValue":"Manual",
"value":"Manual"
},
"Person_Billing_Account__c":{
"displayValue":null,
"value":null
},
"Person_Billing_Account__r":{
"displayValue":null,
"value":null
},
"RecordTypeId":{
"displayValue":null,
"value":"01241000001AT6fAAG"
}
}
}
Above is some JSON.stringified real data returned to me by LWC's getRecord method. As you can see within the fields object, the assumption that every key's value is what we need to send to the back end (which is baked into the other code) is accurate- with the exception of Account. Its value is another object which contains its own fields, id, etc. I leveraged @sfdcfox's code and made an adjustment so we can handle values one relationship away. I'll leave it to whomever comes after me to support walking through > 1 relationship away.
One thing to note is I requested Person_Billing_Account__r.Name from getRecord, but since Person_Billing_Account__c was null, Person_Billing_Acccount__r's value is just null- instead of an object leading to null. To account for this, I just suppress all null values in my code since passing them to the controller doesn't help anything anyway.
Without further ado, here is my adjusted code:
const convertWiredDataToApexSobject = wiredData => {
return {
sobjectType: wiredData.apiName,
Id: wiredData.id,
...extractValues(wiredData.fields)
};
};
const extractValues = fields => {
return Object.keys(fields).reduce((a, f) => {
let { value } = fields[f];
//check if value is object
if (typeof value === "object" && value !== null)
value = {
Id: value.id,
...extractValues(value.fields)
};
//suppress nulls
if (value === null) return a;
a[f] = value;
return a;
}, {});
};
Usage:
//const data = <data from getRecord>
const ApexSobject = convertWiredDataToApexSobject(data);
console.log(JSON.stringify(ApexSobject))
Result:
{
"sobjectType":"Case",
"Id":"500R000000AbnzLIAR",
"Account":{
"Id":"001R000001QN4GRIA1",
"Name":"Bob the Builder"
},
"AccountId":"001R000001QN4GRIA1",
"Origin":"Manual",
"RecordTypeId":"01241000001AT6fAAG"
}