Combining objects recursively in javascript

Currently tackling a React project issue regarding object merging with the setState method. Two objects are involved:

person1 = {
    name: 'ramya',
    age: 21,
    gender: 'f',
    skills:{
        technicalSkills: {
            languages: ['C', 'C++', 'Java'],
            operatingSystems: ['Unix', 'Linux']
        },
        linguisticSkills: {
            toSpeak: ['English', 'Tamil'],
            toRead: ['English']
        }
    },
}

obj2 = {
    skills: {
        linguisticSkills: {
            toRead: ['English', 'Tamil']
        }
    }
}

The objective is to update person1's skills.linguisticSkills to

linguisticSkills: {
                toSpeak: ['English', 'Tamil'],
                toRead: ['English', 'Tamil']
} 

But given changes in skills.linguisticSkills.toSpeak and skills.linguisticSkills.toRead, how can I effectively merge person1 and obj2 in setState for the desired outcome?

UPDATE: _.merge struggles with cases like this:

person1 = {
        name: 'ramya',
        age: 21,
        gender: 'f',
        skills:{
            technicalSkills: {
                languages: ['C', 'C++', 'Java'],
                operatingSystems: ['Unix', 'Linux']
            },
            linguisticSkills: {
                toSpeak: ['English', 'Tamil'],
                toRead: ['English', 'Tamil', 'Telugu']
            }
        },
    }

    obj2 = {
        skills: {
            linguisticSkills: {
                toRead: ['English', 'Tamil']
            }
        }
    }

resulting in the same state as person 1 instead of the expected:

{
        name: 'ramya',
        age: 21,
        gender: 'f',
        skills:{
            technicalSkills: {
                languages: ['C', 'C++', 'Java'],
                operatingSystems: ['Unix', 'Linux']
            },
            linguisticSkills: {
                toSpeak: ['English', 'Tamil'],
                toRead: ['English', 'Tamil']
            }
        },
    }

Answer №1

When working with Lodash, it's important to understand the difference between _.merge() and _.mergeWith(). While _.merge() is recursive in nature, providing a more standard merging behavior, _.mergeWith() allows for more customized control over the merge process.

const person1 = {"name":"ramya","age":21,"gender":"f","skills":{"technicalSkills":{"languages":["C","C++","Java"],"operatingSystems":["Unix","Linux"]},"linguisticSkills":{"toSpeak":["English","Tamil"],"toRead":['English', 'Tamil', 'Telugu']}}}

const obj2 = {"skills":{"linguisticSkills":{"toRead":["English","Tamil"]}}}

const result = _.mergeWith({}, person1, obj2, (objValue, srcValue) => {
  if( _.isArray(srcValue)) {
    return srcValue;
  }
});

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Answer №2

For more information, visit this link: How to deep merge instead of shallow merge?

/**
 * Checking if an item is a simple object.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

/**
 * Merging two objects deeply.
 * @param target
 * @param ...sources
 */
export function mergeDeep(target, ...sources) {
  if (!sources.length) return target;
  const source = sources.shift();

  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }

  return mergeDeep(target, ...sources);
}

// This code snippet was taken from the linked Stack Overflow question with credit to Salakar.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Move the camera left and right, up and down using the arrow keys in WebGL

I am currently working on implementing a basic camera movement system in WebGL using JavaScript and the keyboard to control the camera's movement along the X and Y axes. However, I am facing an issue where the camera moves in world coordinates rather ...

In React, the functionality of rendering components conditionally is not functioning properly

I am looking to conditionally display either the Login component or Menubar component based on the value of the isLogin state. If the isLogin state is false, I want to render the login page. If it is true, I want to render the Menubar page. To achieve thi ...

Encountered an issue while trying to retrieve a value from an object within a

Reviewing the following JSON response: [ {"name": "Afghanistan", ...}, {"name": "country 2" ,...}, {"name": "country 3" ,...}, ] My goal is to extract only country names from t ...

Incorporating an external JavaScript file into an AngularJS project

index.html: <!DOCTYPE html> <html> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"> </script> <script src="./assets/namesController.js"></script> <body ng-app="myApp"> < ...

Experiencing Chrome freezing issues due to a setInterval function in combination with React

Can anyone assist me with a countdown issue using React? I am trying to set the minutes and seconds by clicking on + and - buttons, then passing the seconds to a new variable called tottime. However, when the user clicks on Go!, the countdown should start ...

Three.js: Create a Custom Cube Panorama with Adjustable Orientation (Front, Back, Left, Right, etc.)

For my project, I am implementing a rotating cube panorama image with 6 sides: Check out the example here View the code on GitHub scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 0.1, 100 ); cam ...

Using the ng-src and ng-repeat directives in combination within an if/else statement

Seeking assistance with implementing an if/else statement to display different pictures based on a condition in AngularJS. Here is an example of the controller code: $scope.getFeatureNo = function (thisCase) { if (thisCase.featureno == 1) { ...

React Native can trigger a press event, as long as it is not within

My situation involves triggering an action when clicking on the parent component (TouchableOpacity, for example), but not triggering anything when clicking on the children components (Screen and others). It's similar to preventing bubbling on the web. ...

Utilize Cordova's social share plugin to send a text message containing a variable

I have implemented the social share plugin from Cordova in order to share SMS messages with a specific phone number. <a class = "lft" onclick="window.plugins.socialsharing.shareViaSMS('My cool message', 7767051447, function(msg) {cons ...

Surprising results when using the double less than operator to access a particular index within an Array

When utilizing the shovel operator to append an element to an array in a typical manner, the outcome is as follows: stack = [6,7] result = stack << 9 The value of result after this operation will be [6,7,9] However, if we have the following scena ...

Identifying memory leaks caused by rxjs in Angular applications

Is there a specific tool or technique available to identify observables and subscriptions that have been left behind or are still active? I recently encountered a significant memory leak caused by components not being unsubscribed properly. I came across ...

Adding a fresh item to each index within an array using PHP - what's the best way to do it?

var_export($res) is an array with the following structure. array(0 =>(object) array('user' => NULL, 'courseId' => 18,), 1 =>(object) array('user' =>(object) array('id' =&g ...

Doing an asynchronous function in the route.js file in Node.js

I'm facing an issue with my application that uses nodejs as the backend and has some Python scripts integrated. The problem lies in making the 'PythonShell' function asynchronous, but for some reason, it's not working as expected. In o ...

Utilizing Web Worker threads to enhance performance in Google Maps

Currently, I am experimenting with web worker threads to retrieve directions between various pairs of locations simultaneously and save the data in a file at the end. The process worked smoothly when attempted sequentially. I am using npm live-server to sh ...

The modification of Javascript content type occurring following URL Rewrite

I'm currently working on setting up a Reverse Proxy with ARR and URL rewrite in order to achieve the following redirection: Source: http://localhost/test Destination: http://localhost:83/ The goal is for the final URL displayed to be same as the so ...

Encountering unidentified data leading to the error message "Query data must be defined"

Currently, I'm utilizing Next.js to develop a project for my portfolio. In order to manage the API, I decided to implement both Tanstack query and Axios. The issue arises when attempting to retrieve the data as an error surfaces. Oddly enough, while ...

Looking to add custom Google fonts to your NextJS 13 project? Running into issues with link tags not working as

Attempting to utilize Google Fonts on a project built with Next.js, specifically the latest version 13, but encountering issues with importing Google Fonts like Poppins correctly. In the past, simply adding link tags to either the _document.js or _app.js ...

Display only the background image or color behind a stationary element

Our website features a header with a fixed position that remains at the top of the page while scrolling. The product team has requested a gap or margin between this fixed element and the top navbar. However, when we implemented this gap, users started not ...

Create an array using the keyword "where"

Is it possible in Python to declare an array with the following syntax? arr = [x for x in vec if x < 2] - (Edit: apology for the 'from'. my common error (the eclipse always corrects me)) (or any other statement without an actual loop) ...

Using PHP arrays to create a continuous x-axis in Google charts

I have been using some code that successfully generates a Google line chart with a discrete x-axis based on data from a MySQL table. However, when I attempt to change the column type to "date" in order to create a continuous x-axis, I encounter the followi ...