Reputation: 1529
I am trying to figure out the best way to patch a collection of objects. I am trying to change the sort order of a number of objects and was thinking jsonpatch may be the right approach. My Object Looks Like:
[
{
"ID": "100",
"FirstName": "John",
"LastName": "Smith",
"Email": "[email protected]",
"SortOrder": 1
},
{
"ID": "125",
"FirstName": "John",
"LastName": "Doe",
"Email": "[email protected]",
"SortOrder": 3
},
{
"ID": "50",
"FirstName": "james",
"LastName": "johnson",
"Email": "[email protected]",
"SortOrder": 2
},
]
I created an endpoint that allows a patch request to update multiple objects in the collection using jsonpatch request like this:
[
{
"op": "replace",
"path": "/1/SortOrder",
"value": 2
},
{
"op": "replace",
"path": "/0/SortOrder",
"value": 1
},
{
"op": "replace",
"path": "/2/SortOrder",
"value": 3
}
]
What I want to be able to do is use the ID property in the jsonpatch path. Is that possible with my current object structure? It would look something like:
[
{
"op": "replace",
"path": "/125/SortOrder",
"value": 2
},
{
"op": "replace",
"path": "/100/SortOrder",
"value": 1
},
{
"op": "replace",
"path": "/50/SortOrder",
"value": 3
}
]
What would I have to do to be able to make a patch request like this?
Upvotes: 20
Views: 23772
Reputation: 4428
JSON Patch works exactly as your request if you change json from array to Map<ID, Object>
JSON Patch use index for array and key for map
Upvotes: 0
Reputation: 2351
You can avoid using arrays and just rely on JSON objects. It's not exactly ideal, but you can still rely on jsonpointers really nicely.
So your original document would change to look like:
{
"100": {
"ID": "100",
"FirstName": "John",
"LastName": "Smith",
"Email": "[email protected]",
"SortOrder": 1
},
"125": {
"ID": "125",
"FirstName": "John",
"LastName": "Doe",
"Email": "[email protected]",
"SortOrder": 3
},
"50": {
"ID": "50",
"FirstName": "james",
"LastName": "johnson",
"Email": "[email protected]",
"SortOrder": 2
}
}
Then your JSON PATCH payload can look like:
[
{
"op": "replace",
"path": "/125/SortOrder",
"value": 2
},
{
"op": "replace",
"path": "/100/SortOrder",
"value": 1
},
{
"op": "replace",
"path": "/50/SortOrder",
"value": 3
}
]
If you care about ordering in your JSON array, you can introduce a new field "position" or "index" or whatever you like to maintain ordering.
Upvotes: 1
Reputation: 121
try this function:
export function generateJsonPatch(obj: Object, patchObject = [], parent: string = null): Object[] {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] instanceof Object) {
if (parent) {
parent = parent + '/' + key;
} else {
parent = key;
}
generateJsonPatch(obj[key], patchObject, parent);
} else if (obj[key]) {
let fieldName;
if (parent) {
fieldName = parent + '/' + key;
} else {
fieldName = key;
}
const patchField = { op: 'replace', path: `/${fieldName}`, value: `${obj[key]}` };
patchObject.push(patchField);
}
}
}
return patchObject;
}
// USAGE:
const test = {
'a': '1',
'b': '2',
'c': [{
'd': '4',
'e': '5'
}]
};
generateJsonPatch(test);
// it will generate
// [{ "op": "replace", "path": "/a", "value": "1" },
// { "op": "replace", "path": "/b", "value": "2" },
// { "op": "replace", "path": "/c/0/d", "value": "4" },
// { "op": "replace", "path": "/c/1/e", "value": "5" }]
Upvotes: -4
Reputation: 741
Based on the Json pointer RFC, there is no way to select an element from an array by some property. Since JSON Patch uses JSON Pointer, you are out of luck.
It is too bad the JSON Patch folks didn't select JSON Path, or something similar, for the selection language.
Upvotes: 31