How to Merge JSON Objects

How to Merge JSON Objects Without Losing Existing Data

No idea how to do this using a merge operation so that existing data isn’t lost.

The ability to Merge JSON objects is a commonly occurring operation in JavaScript that is performed in API processing, user preferences, application configuration, structured data, etc. But if two objects are merged incorrectly, then properties or values may be overwritten, would-be properties may be deleted, or nested data may vanish.

To deeply understand how to merge without discarding any existing information, you should be familiar with JavaScript object properties, the spread operator, and cases where a deep merging of objects is needed.

In this guide, you will learn how to join JSON objects in safe ways, how to keep existing properties, work with nested objects, avoid common pitfalls and select the appropriate merge method for your project!

What Does ‘Merge JSON Objects’ Mean?

Combining JSON Objects is a process which we can combine the properties of two or more objects and create a new object.

You have an existing user object, for instance:

const existingUser = {
  name: "John",
  email: "john@example.com"
};

You get further information:

const newData = {
  age: 30,
  city: "New York"
};

You need to merge two of the objects but don’t want to lose any information.

The resulting shape would resemble this one:

{
  name: "John",
  email: "john@example.com",
  age: 30,
  city: "New York"
}

It could be done in a number of ways in JavaScript, such as the spread operator and the built-in object.assign(), but also even implemented as a writing of a custom deep merge function.

The best approach, however, depends on your data structure and whether or not you wish to retain nested properties.

Is it possible to merge two JSON objects?

The acronym for JSON is JavaScript Object Notation. Is a text-based format for storing and exchange structured data.

It is not possible to merge JSON text as such with the JavaScript object operators. To use the JSON strings, you will first need to convert them into values that can be used as objects in JavaScript.

For example:

const json1 = '{"name":"John","age":30}';
const json2 = '{"city":"New York","country":"USA"}';

const object1 = JSON.parse(json1);
const object2 = JSON.parse(json2);

const merged = {
  ...object1,
  ...object2
};

console.log(merged);

Output:

{
  name: "John",
  age: 30,
  city: "New York",
  country: "USA"
}

The JSON.parse() method parses JSON text, constructing the correspondingly described object in the JavaScript language. The resulting objects’ properties are then aggregated using the spread operator.

In order to send the merged object as a JSON you can return it to string as:

const mergedJson = JSON.stringify(merged);

console.log(mergedJson);

Output:

{"name":"John","age":30,"city":"New York","country":"USA"}

Be mindful of this, as JSON.parse() will throw an error if given incorrect JSON. Verify or properly deal with untrusted input of JSON data.

You can use the Spread Operator to merge two JSON Objects.You merge two JSON Objects using the Spread Operator.

Spread Operator (…), one of the easiest and most widely used object merging techniques in the Modern JavaScript.

Generates a new object out of the enumerable own properties of the given objects.

Example: Merging Two Objects

const existingData = {
  name: "Alice",
  age: 25
};

const additionalData = {
  city: "London",
  country: "UK"
};

const mergedData = {
  ...existingData,
  ...additionalData
};

console.log(mergedData);

Output:

{
  name: "Alice",
  age: 25,
  city: "London",
  country: "UK"
}

Spread operator copies properties both objects to a new object. All four properties are preserved since the objects have distinct property names.

What If Properties Share A Name?

Potential problem is if both objects have the same property.

const existingData = {
  name: "Alice",
  age: 25
};

const updatedData = {
  age: 30
};

const mergedData = {
  ...existingData,
  ...updatedData
};

console.log(mergedData);

Output:

{
  name: "Alice",
  age: 30
}

The second object looks more inferior in the expression, and it changes the original value of the type `age.

Given by the action is a last write wins merge.

Normally this is what is wanted if the new data should be given priority over the old data and other unrelated data properties should stay the same.

But, if the original value should never have to be overwritten then a different strategy is required.

Retain Current values in situations of conflict

The order of the objects can be inverted:

const mergedData = {
  ...updatedData,
  ...existingData
};

When the property names clash the existing object’s values are used first.

For example:

const existingData = {
  name: "Alice",
  age: 25
};

const updatedData = {
  age: 30,
  city: "London"
};

const mergedData = {
  ...updatedData,
  ...existingData
};

console.log(mergedData);

Output:

{
  age: 25,
  city: "London",
  name: "Alice"
}

This strategy is done to retain existing values and add new values that don’t exist.

Important: The spread expression is ordered and this affects which values are winners. Choose the order according to your application’s requirements.

Using Object.assign() to merge objects.

Object.assign() is also a way to merge objects in JavaScript.

This inserts the enumerable own properties that have values of one or more source objects into a target object.

Basic Example

const existingData = {
  name: "David",
  age: 28
};

const additionalData = {
  city: "Toronto",
  country: "Canada"
};

const mergedData = Object.assign(
  {},
  existingData,
  additionalData
);

console.log(mergedData);

Output:

{
  name: "David",
  age: 28,
  city: "Toronto",
  country: "Canada"
}

The first argument, {}, refers to the object that you are attempting to act upon. All other arguments are the objects or values to be copied from into the target object or value.

Empty object used for target, preserves original source objects.

Why Not Use the Existing Object as the Target?

Consider this example:

const existingData = {
  name: "David",
  age: 28
};

const additionalData = {
  age: 35,
  city: "Toronto"
};

Object.assign(existingData, additionalData);

console.log(existingData);

Output:

{
  name: "David",
  age: 35,
  city: "Toronto"
}

This modifies the existingData in place. Original Age is erased, and source object is changed.

Some other part of your application may rely on that object and changing it may lead to incorrect behaviour.

Instead, use:

const mergedData = Object.assign(
  {},
  existingData,
  additionalData
);

This will return a new top-level object leaving the original top-level object intact.

Notice that Object.assign() like the spread, does shallow copy.

In order to understand this issue, it is important to first understand why Shallow Merging can lose Nested Data.

When merging objects using JSON, one of the most common pitfalls is incorrectly merging nested objects.

It does not.

Let’s take a look at this collection of objects.

const existingData = {
  name: "Sarah",
  settings: {
    theme: "dark",
    notifications: true
  }
};

const updatedData = {
  settings: {
    theme: "light"
  }
};

const mergedData = {
  ...existingData,
  ...updatedData
};

console.log(mergedData);

Output:

{
  name: "Sarah",
  settings: {
    theme: "light"
  }
}

You can see that the attribute notifications is missing in the merged.

Why?

The spread operator only spread the top-level properties. Since both objects have a property named settings, the whole nested object from the property value updatedData is replaced with the original one.

This is not a bug. It is being, because a shallow merge normally behaves like this.

This section discusses how to keep nested properties.Keeping Nested Properties

If you want to update only the theme and not the notification setting then you will need to merge in each in an individual manner.

const mergedData = {
  ...existingData,
  settings: {
    ...existingData.settings,
    ...updatedData.settings
  }
};

console.log(mergedData);

Output:

{
  name: "Sarah",
  settings: {
    theme: "light",
    notifications: true
  }
}

This way, you keep everything the same property-wise and just update the theme.

If the amount of nesting is limited (one or two levels), you may be able to separately spread one or more of the relevant objects in a clear and effective way.

But, if you have objects that are many layers deep then a deep merge function might be better suited to be written and used a lot.

4. Convert Nested JSON Object without Overshadowing any existing data.

Deep merge: merge deeply nested objects recursively and not shallowly (at the first found matching property).

For instance, take an application configuration as follows:

const defaultConfig = {
  app: {
    name: "My Application",
    version: "1.0"
  },
  settings: {
    theme: "dark",
    language: "en",
    notifications: true
  }
};

const userConfig = {
  settings: {
    theme: "light"
  }
};

A shallow merge would drop out the language and notification properties, and replace the whole settings object.

Those can be kept using a deep merge when updating the theme.

A depth-first recursive deep_merge function in PL/SQL.

The next example works well for JSON like objects that have plain objects, array, and primitive values.

function deepMerge(target, source) {
  const result = { ...target };

  for (const key of Object.keys(source)) {
    const sourceValue = source[key];
    const targetValue = result[key];

    if (
      sourceValue !== null &&
      targetValue !== null &&
      typeof sourceValue === "object" &&
      typeof targetValue === "object" &&
      !Array.isArray(sourceValue) &&
      !Array.isArray(targetValue)
    ) {
      result[key] = deepMerge(targetValue, sourceValue);
    } else {
      result[key] = sourceValue;
    }
  }

  return result;
}

Now, combine the configuration objects:

const mergedConfig = deepMerge(
  defaultConfig,
  userConfig
);

console.log(mergedConfig);

Output:

{
  app: {
    name: "My Application",
    version: "1.0"
  },
  settings: {
    theme: "light",
    language: "en",
    notifications: true
  }
}

At the start, the top-level properties of the target are copied. Then it begins working through each one of the properties, from the source.

If both the corresponding values are plain object-like structures, it recursively merges them. If it is not, it will be based on the source value.

Important: This is illustrative deep merge for JSON like data and isn’t a general purpose production ready merge utility. It doesn’t validate prototypes for objects nor does it degrade or deal with circular references. For arbitrary JavaScript objects or bits of unknown data use a library that you have maintained, and explicitly written merging rules for.

Also, this example is not used to combine elements of an array, but rather to replace arrays. It may be appropriate for configuration changes, however, it may need to be different for your App.

In this section, she examines ways to safely merge multiple JSON objects.

A time will come when you will need to combine three or more objects in your system – default preferences, new user preferences, your saved settings, etc.

When there’s no need for a deep merge, the spread operator makes this easy.

const defaultSettings = {
  theme: "light",
  language: "en",
  notifications: true
};

const savedSettings = {
  theme: "dark",
  language: "fr"
};

const newSettings = {
  notifications: false
};

const mergedSettings = {
  ...defaultSettings,
  ...savedSettings,
  ...newSettings
};

console.log(mergedSettings);

Output:

{
  theme: "dark",
  language: "fr",
  notifications: false
}

The objects are lent out from left to right.

The initial values are set by the default setting, the later values override the previous ones for any values stored in the object and the previous values in the object override the default ones.

It is a good pattern for storing configuration details, in application preferences and for API data processing.

Keep in mind that the spread operator doesn’t merge nested properties in.

6. Is it Better to Merge Arrays vs. Replace Them?

Special attention should be paid in arrays when pairing to JSON objects.

Let’s take this case as an example:

const existingData = {
  name: "Alex",
  skills: ["JavaScript", "HTML"]
};

const updatedData = {
  skills: ["CSS"]
};

const mergedData = {
  ...existingData,
  ...updatedData
};

console.log(mergedData);

Output:

{
  name: "Alex",
  skills: ["CSS"]
}

The existing skills array is replaced.

When an update is a full update of a field, often this is the right behavior. If however the elements of the current array should be preserved, you can perform this combination of the arrays explicitly.

const mergedData = {
  ...existingData,
  ...updatedData,
  skills: [
    ...existingData.skills,
    ...updatedData.skills
  ]
};

console.log(mergedData);

Output:

{
  name: "Alex",
  skills: ["JavaScript", "HTML", "CSS"]
}

This will leave the existing skills and add the new value.

If it’s not OK to have elements which occur more than once use Set:

const mergedData = {
  ...existingData,
  ...updatedData,
  skills: [
    ...new Set([
      ...existingData.skills,
      ...updatedData.skills
    ])
  ]
};

This eliminates duplicates primitive values while maintain the order of its appearance.

But, the merge of arrays should adhere to the data model. Some arrays are complete lists to be replaced, and some are collections to be added (appended), to be deduplicated or to be matched with an identifier.

Not all applications will have one array merging strategy that is suitable.

  1. Advanced Format Functions for Lists of Numbers

A major effect to take into consideration is exactly how to offer with ‘undefined’ and ‘null’ when merging.

These are different values in JavaScript.

  • The value null is an explicit value indicating the lack of value.
  • The term undefined is often used to mean that something has not been determined, or, in other words, that the value is missing.

Consider this example:

const existingData = {
  name: "Emma",
  age: 29,
  city: "Paris"
};

const updatedData = {
  age: undefined,
  city: null
};

const mergedData = {
  ...existingData,
  ...updatedData
};

console.log(mergedData);

The result is:

{
  name: "Emma",
  age: undefined,
  city: null
}

Note that even if the age property’s value is undefined in the lines that follow, the value for the age property in the object to the left is overwritten.

When a value that is coming into the new object is undefined, you can filter out the values that you wish to retain in the new object before merging.

const filteredData = Object.fromEntries(
  Object.entries(updatedData).filter(
    ([key, value]) => value !== undefined
  )
);

const mergedData = {
  ...existingData,
  ...filteredData
};

console.log(mergedData);

Output:

{
  name: "Emma",
  age: 29,
  city: null
}

In this case, the presentages age is maintained, and the value of city is deliberately set to null.

Note that the filtering is only applied to the properties at the first level. Recursive filtering strategy (or appropriate merge utility if your data contains some nested objects) would be required to apply the same rule at each level.

So, What Happens When You Convert Undefined to JSON?

When coerced to a string, the JSON.stringify method behaves differently on different undefined values.

const data = {
  name: "Emma",
  age: undefined
};

console.log(JSON.stringify(data));

Output:

{"name":"Emma"}

If an object attribute is undefined, then it will not be included in the JSON output.

But undefined elements in the array are quoted as null:

console.log(JSON.stringify([1, undefined, 3]));

Output:

[1,null,3]

This difference would help when you are combining data that is going to be passed to API or will be housed as JSON.

Don’t alter/change the original object by mistake.

When a safe merge is used, the new merge should typically not and should not unexpectedly change the original data.

For instance, this alters the already existing object:

Object.assign(existingData, updatedData);

This is also true for direct property assignments:

existingData.name = "Updated Name";

These operations are suitable if you want to make a mutation on purpose, but can be a problem in applications that share object references.

A less risky alternative when doing a shallow merge is:

const mergedData = {
  ...existingData,
  ...updatedData
};

This results in a new top level object.

But, does not perform a deep clone on nested objects. If both objects have a nested reference, and the nested reference isn’t replaced, the resulting object may share a nested reference with the original.

If the data you want to clone is JSON compatible, you can use structuredClone() to clone it in supported modern JavaScript environments:

const copiedData = structuredClone(existingData);

const mergedData = {
  ...copiedData,
  ...updatedData
};

This example copies the data from the original source in deep copy then shallow merges. Does not merge recursively when nested properties given in updatedData.

For regular json-representable data it is possible to use:

const copiedData = JSON.parse(
  JSON.stringify(existingData)
);

However, there are drawbacks with this cloning method, which is based on JSON. It excludes any undefined object properties, some values like dates are serialised to strings and it will not allow any circular reference in the object graph.

If the data types and behavior of structuredClone() meet your needs, use it.

10. Errors to Avoid When Merging JSON Objects

The common errors give you insight into how not to lose data.

Mistake #1: Assuming the Spread Operator is a Deep Merge

The spread operator copies only top-level properties. Nested objects with identical keys are not recursively merged.

Solution: Explicitly merge nested objects or use an appropriate deep merge function.

Merge Order – Mistake #2 – Reverse the Merge Order

If there are two or more elements in the properties with the same name, the latter one (the last value) is used.

const merged = {
  ...newData,
  ...existingData
};

This prioritises values that exist over new values.

There are two points of interest in this example. First, both old and new values need to be taken into account and a decision made as to which should take precedence before the order is decided.

Mistake #3: Changing the Original Object

Object.assign(existingData, newData) will change the existingData object.

Solution: You can rely on an empty object as the target, or the spread operator, if you want a new top-level object.

Problem #4: Mismatching Arrays (no obvious pattern)

The default merge is a shallow merge, meaning that arrays are compacted.

Solution: Make a decision about replacing, appending, deduplicating, or merging by item ID of the array.

Writing: Mistake 5 – Undefined Values

Although a property may vanish when the object is serialized as a JSON string, an incoming undefined can set the property in a JavaScript object.

Solution: Filter or process undefined values as desired for your application’s update rules.

Mistake 3/6: Using JSON Strings as JavaScript Objects.

It is not possible to merge JSON text in a similar manner to merging parsed objects (using object spread).

Solution: first, any JSON strings which are extra good should be parsed; second, any objects which stay are combined; final, the rest is serialized if a necessity arises.

Mistake 7: To assume a random input.

Custom merge function may have unexpected behaviour with arrays, special objects or untrusted objects with atypical property structure.

Solution: Check incoming data, specify acceptable types of objects and consult a reliable library for dealing with complex or data supplied by external objects.

10. Which method to merge two JSON Objects should you pick?

The choice of the right one will depend on how your data is organized and what you want to do with it.

MethodBest Use CaseMain Limitation
Spread operator (...)Simple, shallow mergesreplaces nested objects
Copying properties into a targetMutates the target object
Manual, nested spreadUpdates a few known-nested propertiesStarts to become repetitive when dealing with deep structures
Recursively merge plain objectsCustom deep mergeRules must be established for arrays and special values.
Complex or reusable merging requirementsBehavior is a function of the library & configurationMerge Utility Library

The spread operator is the easiest for most of the projects that beginning coders will do.

For deeply nested configurations, implement a deep merge explicit strategy (keeps the properties wanted).

With respect to setting values, it is also crucial to determine whether the values received are a partial update or a complete replacement. That classification is sometimes more important than the specific JS approach that you may take.

Answers to questions that are frequently asked.

How to merge two JSON objects and keep the properties in JavaScript?

You can use the spread operator:

const merged = {
  ...object1,
  ...object2
};

This leaves the properties, that are different, the same but properties of same name are assigned from the second Object. In the case of “nested objects” merge using a deep merge strategy if a nested object property needs to be retained.

2. Does the JavaScript spread operator override the data?

Yes. If two objects have the same property name, then the value from the object spread last will be used.

const merged = {
  ...{ name: "John" },
  ...{ name: "David" }
};

The resultant name is ‘David’.

3. What do to do to merge objects so that I can retain the current values?

Add the object at the end:

const merged = {
  ...newData,
  ...existingData
};

This ensures that if there are any name clashes between properties, then the incoming value is applied as an update to the existing value. Any properties that appear only in newData are added.

4.What is the difference between shallow merge and deep merge?

A shallow merge will only merge top level properties. If some nested property exists in two objects, the latter object’s nested value would be substituted for the former.

Deep merge recursively merges nested plain objects, discarding nested properties which are not present on both sides.

5. Now how do I combine nested JSON objects with the spread operator?

Yes, but you will have to publish the nested objects individually.

const merged = {
  ...oldData,
  settings: {
    ...oldData.settings,
    ...newData.settings
  }
};

This will not remove existing settings which aren’t specified in the newData.settings.

6. Is Object.assign( ) preserving the original object?

Nowhere when original object is as target.

Object.assign(existingData, updatedData);

This modifies existingData.

To define a top level object simply:

const merged = Object.assign(
  {},
  existingData,
  updatedData
);

7. How to merge the JSON arrays without discarding the elements in it?

Arrays can be explicitly combined with spread:

const mergedArray = [
  ...oldArray,
  ...newArray
];

Let’s you assign an array to a property within an object where there is a merge of two arrays in the object. Select to keep or remove duplicates as needed.

9. How to merge JSON objects, but ignore undefined value?

If you have top level properties filter out whatever is undefined before merging:

const filtered = Object.fromEntries(
  Object.entries(newData).filter(
    ([key, value]) => value !== undefined
  )
);

const merged = {
  ...oldData,
  ...filtered
};

This allows explicit values of null and this preserves the existing value in case that the value is undefined.

10. Is it possible to combine two strings in the form of json using JSON.parse()?

No, JSON.parse is a function that turns a text literal that represents JSON into a JavaScript value. Both strings must be parsed, the objects merged, and, if the merged result is to be returned as JSON string, then JSON.stringify must be used.

10. How to safely merge deeply-nested JSON objects?

Explicitly merge the nested properties you wish to preserve, for simple structures. If you have more complicated structures, utilize a well-tested deep merge function library with the ability to specify how to merge arrays, null, and missing values.

Verify outside information and make sure you select the appropriate merge strategy for your application.

Key Takeaways

  • When only shallow merging is needed use the spread operator in a simple object merge.
  • Understand Property Precedence: properties with the same name from later objects overwrite earlier object properties.
    You should use nested spreads or deep merging if you want to retain any existing nested properties.
  • Do not tackle accidental mutation by altering a target object when it is not necessary.
  • Deliberately select an array approach (replacement/deduplication, concatenation or inserting by identifier).
    Be careful to deal with ‘null’ and ‘undefined’; since they mean something and are serialized differently.
    Don’t use JSON.stringify on the final object just when you need its JSON representation, and don’t merge until you’ve parsed / stringified any JSON strings.
  • Data coming in should be validated and if you are dealing with complex structures, then use a tested merge utility.

Safe JSON object merging isn’t opportunity to combine properties only. It’s about knowing what values to maintain, which to change and how to handle nested structures.

Setting out those guidelines makes it easier to select the appropriate merging solution in JavaScript and to update data in your applications and avoid losing vital information.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *