-2

Let's suppose I have an API response that looks like this:

const data = {
  users: [
    { name: "John", teams: [{ name: "Liverpool" }] },
    { name: "Sam", teams: [{ name: "MC" }, { name: "United" }] },
  ],
  photos: [
    { id: "123", types: ["JPG", "PNG"], comments: [{ description: "sample photo" }] },
  ],
};

I want to transform it by adding the rid property to each object.

const data = {
  rid: "ABC",
  users: [
    { rid: "ABC", name: "John", teams: [{ rid: "ABC", name: "Liverpool" }] },
    { rid: "ABC", name: "Sam", teams: [{ rid: "ABC", name: "MC" }, { rid: "ABC", name: "United" }] },
  ],
  photos: [
    { rid: "ABC", id: "123", types: ["JPG", "PNG"], comments: [{ rid: "ABC", description: "sample photo" }] },
  ],
};

How can I do so? I think there is some kind of recursion involved but I haven't been able to draft a solution?

Thanks.

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Ravgeet Dhillon
  • 532
  • 2
  • 6
  • 24
  • Does this answer your question? [How can I access and process nested objects, arrays or JSON?](https://stackoverflow.com/questions/11922383/how-can-i-access-and-process-nested-objects-arrays-or-json) – jabaa May 17 '22 at 17:09
  • @jabaa I know these basics but my problem is a bit trickier. I want to add a property to each object wherever they are in a JSON structure. – Ravgeet Dhillon May 17 '22 at 17:13
  • The accepted answer in the duplicate explains how to traverse all properties in a nested, dynamic object with unknown depth. Can you elaborate why this doesn't solve your problem? – jabaa May 17 '22 at 17:14
  • 1
    @jabaa: I think you're pushing too hard on that duplicate. While Felix Kling's answer is one of the jewels of the Javascript topic and is very educational, it is a stretch to say that it offers an answer to this particular question. There are other reasons to dislike this question, especially the lack of an attempt on the OPs part, but that is independent of the duplication question. – Scott Sauyet May 20 '22 at 13:08
  • @ScottSauyet I'm pushing because Stack Overflow is becoming a code writing service. You can find the same questions 10 times a day with a little different code or data structure. Do we really need a new question for each new property? It's always the same approach. – jabaa May 20 '22 at 16:02
  • @ScottSauyet Asking, answering, accepting and upvoting the same questions and answers with little different data structures wastes this plattform, encourages more of those questions and answers and hides the really good ones. – jabaa May 20 '22 at 16:17
  • 1
    @jabaa: But if you're going to close a question as a duplicate, it should not be with a fairly generic answer that would take significant work to convert into a reasonable solution to the current question. I wouldn't be surprised if there is a duplicate out there closer to this one. I just don't think that's the right one. – Scott Sauyet May 20 '22 at 16:52
  • @ScottSauyet In the other answer you can find all details and techniques to solve this problem. The OP can still elaborate the difference between this question and the linked question, show the attempt, and ask a specific question to a specific problem. "Write the code to transform structure A to structure B" isn't a specific question, and was asked hundreds of times alone in this year. Answering this question isn't useful for future users and this community, in my opinion. – jabaa May 20 '22 at 23:45

3 Answers3

1

First off, in StackOverflow, you should always show your own work. Even if you weren't able to get a complete solution, please show us what you've tried and tell us where it seemed to go wrong. I would not be answering this question except that there are already two other reasonable answers here.


I have a strong aversion to modifying input data, so I wrote a version that creates a copy with that property included on all Object nodes. It looks like this:

const addProp = (name, val) => (o) =>
  Array .isArray (o)
    ? o .map (addProp (name, val))
  : Object (o) === o
    ? Object .fromEntries ([
        [name, val], 
        ...Object .entries (o) .map (([k, v]) => [k, addProp (name, val) (v)])
      ])
  : o

const data = {users: [{name: "John", teams: [{name: "Liverpool"}]}, {name: "Sam", teams: [{name: "MC"}, {name: "United"}]},], photos: [{id: "123", types: ["JPG", "PNG"], comments: [{description: "sample photo"}]}]}

console .log (addProp ('rid', 'ABC') (data))
.as-console-wrapper {max-height: 100% !important; top: 0}

We process in three ways, based on whether our input is an Array, an Object, or something else. If it's neither, we return the value intact. If it's an array, we map a recursive call to the same function over its values. For an object, we split it into name-value pairs, mapping the values with a recursive call and adding one for our new property, then we fold these name-value entries back into an object.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • I completely agree with you but the thing is that my implementation was pretty bad as compared to the answers posted here. – Ravgeet Dhillon May 20 '22 at 13:41
  • 1
    Sure, but next time share it anyway. People here don't want to feel they're being abused. Showing a willingness to do the work yourself is important. – Scott Sauyet May 20 '22 at 13:46
0

Firstly the OP is not going to alter a JSON object. JSON is a string based standardized data interchange format and a JavaScript namespace with static methods.

But the OP is going to recursively traverse/walk a JSON-conform object-type.

Thus the implementation of such a function needs to take into account just object-types and arrays.

In case of an array-type the recursive call takes place forEach array-item. In case of an object-type all values of the object's own enumerable keys/properties will be processed recursively.

For any object-type in addition the assignment of a provided custom object (one or more entries) takes place.

The beneath provided function provides as feature the possibility to define the minimum object-level from where an assignement is going to be applied.

function recursivelyAssignDataToEveryObjectType(type, data, startLevel = 0, level = 0) {
  if (Array.isArray(type)) {
    type
      .forEach(item =>
        recursivelyAssignDataToEveryObjectType(item, data, startLevel, level + 1)
      );
  } else if (type && 'object' === typeof type) {
    Object
      .values(type)
      .forEach(value =>
        recursivelyAssignDataToEveryObjectType(value, data, startLevel, level + 1)
      );
    if (level >= startLevel) {
      Object.assign(type, data);
    }
  }
}

const data = {
  users: [
    { name: "John", teams: [{ name: "Liverpool" }] },
    { name: "Sam", teams: [{ name: "MC" }, { name: "United" }] },
  ],
  photos: [
    { id: "123", types: ["JPG", "PNG"], comments: [{ description: "sample photo" }] },
  ],
};
recursivelyAssignDataToEveryObjectType(data, { rid: "ABC" }, 2);

console.log({ data });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • 1
    Code-only answers aren't useful. They will encourage cargo-cult programming. Answers to code writing services are not useful for this platform. They will encourage more questions of this type. There is a canonical answer for this type of questions that describes how to solve such problems. – jabaa May 17 '22 at 17:18
  • My updated explanation: Answers to code writing services are not useful for this platform. They will encourage more questions of this type. There is a canonical answer for this type of questions that describes how to solve such problems. Duplicates make it more difficult to find that answer. No reason to waste Stack Overflow with more and more answers to the same question with a little different code. – jabaa May 17 '22 at 22:14
  • @jabaa ... 1/2 ... out of curiosity ... quote: _"Duplicates make it more difficult to find that answer. No reason to waste Stack Overflow with more and more answers to the same question with a little different code."_ ... by your own personal standards/agenda/opinion, how could you then give an answer to ... [_"what is a reliable way to validate if this string is valid json?"_](https://stackoverflow.com/questions/72133878/what-is-a-reliable-way-to-validate-if-this-string-is-valid-json/72133985#72133985) ... – Peter Seliger May 18 '22 at 10:06
  • @jabaa ... 2/2 ... when one can find [exactly the same code with the first hit](https://stackoverflow.com/a/3710226/2627243) of following search ... [\[javascript\] check valid json](https://stackoverflow.com/search?q=%5Bjavascript%5D+check+valid+json) whereas the above answer provides a solution which exactly covers the OP's requirements and provides a detailed explanation how to achieve it. – Peter Seliger May 18 '22 at 10:06
  • I didn't know this duplicate, but I posted the comment with duplicate for this question before you answered it. I wouldn't answer a question that contains a comment with a link to a duplicate. – jabaa May 18 '22 at 10:08
  • But you're right. We both should vote to close the other question as duplicate. I did it. – jabaa May 18 '22 at 10:10
0

You just need to iterate through object with recursive function.

Try below snippet.

const data = {
  users: [
    { name: 'John', teams: [{ name: 'Liverpool' }] },
    { name: 'Sam', teams: [{ name: 'MC' }, { name: 'United' }] },
  ],
  photos: [
    { id: '123', types: ['JPG', 'PNG'], comments: [{ description: 'sample photo' }] },
    { key: null }, // Fixed null values
  ],
}

function addProperty(obj, key, val) {
  if (!obj || typeof obj !== 'object') return
  if (!Array.isArray(obj)) obj[key] = val
  Object.values(obj).forEach((obj) => addProperty(obj, key, val))
}

addProperty(data, 'rid', 'ABC')

console.log(data)
Yosvel Quintero
  • 18,669
  • 5
  • 37
  • 46
MORÈ
  • 2,480
  • 3
  • 16
  • 23
  • 1
    Answers to code writing services are not useful for this platform. They will encourage more questions of this type. There is a canonical answer for this type of questions that describes how to solve such problems. – jabaa May 17 '22 at 17:24
  • 2
    @RavgeetDhillon ... the above implementation will fail with a `TypeError` for any `null` value within the data structure. In addition it adds the entry at object root and to all first level objects whereas the OP's requirements show the additional property at object level 2 and higher. – Peter Seliger May 17 '22 at 17:50
  • Fixed `null` values and added dynamic parameters – Yosvel Quintero May 17 '22 at 18:02