如何通过最简方式实现对象间的PATCH式更新?
Alright, let's tackle this problem step by step. The core requirement is to update the original array (o1) using changes from the update array (o2), while keeping existing fields intact and ignoring new fields from the update (we'll prioritize this strict rule first, with a simplified alternative if adding new fields is acceptable).
Key Rules Recap
- If a field doesn't exist in
o2, keep the original value fromo1 - If
o2has a field thato1doesn't, don't add it too1(strict rule we'll follow first) - Only update fields that exist in both
o1ando2
Solution Code (JavaScript)
Here's a clean implementation that sticks to your requirements perfectly:
const o1 = [{ key: "A", content: { field1: "sample text A", field2: "another sample text A" } }, { key: "B", content: { field1: "sample text B", field2: "another sample text B" } }]; const o2 = [{ key: "A", content: { field1: "updated sample text A", field3: "added text A" } }]; const o3 = o1.map(originalItem => { // Find the matching update entry using the `key` property const updateEntry = o2.find(update => update.key === originalItem.key); // No matching update? Return the original item as-is if (!updateEntry) return originalItem; // Create a copy of the original content to avoid mutating the original object const updatedContent = { ...originalItem.content }; // Only update fields that already exist in the original content Object.keys(updateEntry.content).forEach(field => { if (field in updatedContent) { updatedContent[field] = updateEntry.content[field]; } }); // Return the updated item (keeping other properties like `key` unchanged) return { ...originalItem, content: updatedContent }; }); console.log(o3);
How This Works
- Immutable Update with
map: We usemapto generate a new array instead of modifying the originalo1—this is a best practice to avoid unintended side effects. - Match Entries by
key: For each item ino1, we look for a corresponding entry ino2using the sharedkeyproperty. - Preserve Original Data: We make a copy of the original
contentobject so we don't alter the source data accidentally. - Selective Field Updates: We loop through all fields in the update's
content, but only overwrite values if the field already exists in the originalcontent. This ignores new fields likefield3from your example. - Return Updated/Original Items: Items without a matching update are returned unchanged, while matched items get their existing fields updated as needed.
Simplified Version (If Adding New Fields Is Allowed)
If you're okay with adding new fields from o2 to o1 to simplify the code, here's a much shorter approach using object spreading:
const o3 = o1.map(originalItem => { const updateEntry = o2.find(update => update.key === originalItem.key); return updateEntry ? { ...originalItem, content: { ...originalItem.content, ...updateEntry.content } } : originalItem; });
This will add new fields like field3 to o1's content, but it’s a concise alternative if the "no new fields" rule isn’t strictly required.
内容的提问来源于stack exchange,提问作者Lajtovo

