0

I have 3 different jsons, I need to extrapolate some data from each and create a new json with it. The three jsons have an id identifier in common, a unique identifier, so We could use that as a match since they are actually three different big jsons.

On json one we have "id":"265", on two and three "article_id":"265", so these can be the reference point when we loop.

I never worked with json this way so I wouldn't know how to approach it. I have put jQuery and JS as tags as they're what I know best.

1

{  
   "id":"265",
   "title":"Battle of Gettysburg",
   "page_id":"4849",
   "language_id":"en",
   "original_time":"July 1\u20133, 1863"
}

2

{  
   "id":"185",
   "original_name":"United States",
   "country_id":"24",
   "article_id":"265"
}

3

{  
   "id":"73",
   "month":"July",
   "year":"1863",
   "suffix":"",
   "article_id":"265"
}

So the end result I am looking for is a single json exactly like this, we take id and title as objects from json 1, then we grab original_name from json two and year object from json three and we'll have:

{
   "id":"265",
   "title":"Battle of Gettysburg",
   "original_name":"United States",
   "year":"1863"
}

NOTE

The json above are just examples, in reality they are three huge lists, what I could do (manually), is to join them in order to have a single json.

rob.m
  • 9,843
  • 19
  • 73
  • 162
  • Does your code base already contain classes that correspond to each of these JSON strings? – John Wu May 29 '18 at 19:44
  • @JohnWu tbh since I wouldn't know the approach, I haven't started to put down some code, so seriously, what you see in the question is what I've got for now. Thing is these json are really big, so this is a simplified version – rob.m May 29 '18 at 19:45
  • Maybe this will help: https://stackoverflow.com/questions/16507222/create-json-object-dynamically-via-javascript-without-concate-strings?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – spider22 May 29 '18 at 19:48
  • Please don't put a language tag just because you are good at it. You should put those tags which are relevant to your question. In what context you are trying to manipulate such JSON data is not clear from your post. – Bhesh Gurung May 29 '18 at 19:52
  • 1
    Note that you are likely working with objects, not strings (which is what JSON is). ([obligatory link to There's no such thing as a JSON Object for more](http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/)) – Heretic Monkey May 29 '18 at 19:57
  • Just to confirm: is it correct that each of these three json files contains a list of these objects (and you've only shown one example of each so we can see the structure); and that you need to match items with the same ID in each of the three files? Or is it really just three large individual objects that you need to grab selected fields from to make one output object? – Daniel Beck May 29 '18 at 19:58
  • @DanielBeck yes exactly – rob.m May 29 '18 at 20:00
  • sorry, you answered while i was mid-comment-edit :) It's lists, then. cool – Daniel Beck May 29 '18 at 20:01
  • @DanielBeck yes indeed they are three large individual objects that I need to grab selected fields from to make one output object. These three have in common the ID as per the question, so this would help when looping i guess – rob.m May 29 '18 at 20:02
  • Are these objects actually elements of arrays, and you need to match up the IDs? – Barmar May 29 '18 at 20:03
  • Wait. So it's *not* three lists? Just three objects, total? – Daniel Beck May 29 '18 at 20:14
  • @DanielBeck tbh they are three lists but I could join them manually, by adding a comma :) – rob.m May 29 '18 at 20:18

5 Answers5

1

Essentially what you have to do is mimic a SQL JOIN using JavaScript objects:

  1. Use JSON.parse() on all three JSON collections to turn them into arrays of objects.
  2. Iterate through JSON 1 objects; for each object...
  3. Iterate through JSON 2 objects, testing if article ID matches the ID from JSON 1 that we are iterating over. Save this object.
  4. Iterate through JSON 3 objects, testing if ID matches the ID of the object we found from JSON 2. Save this object.

After you have all three objects, make a new object literal that contains only the fields you want:

{
  Id: obj1.id,
  Title: obj1.title,
  Original_name: obj2.original_name,
  Year: obj3.year
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
ouni
  • 3,233
  • 3
  • 15
  • 21
1

There is some terminology confusion here; based on your comments you could be asking one of two very different questions. Fortunately one of them is very simple to answer so let's do both.

(I am handwaving past the details of loading json strings into the browser and converting them into javascript objects.)

If you have three objects

...then this is just a matter of plucking out the fields you need individually when constructing an output object:

var in1 = {
  "id": "265",
  "title": "Battle of Gettysburg",
  "page_id": "4849",
  "language_id": "en",
  "original_time": "July 1\u20133, 1863"
};

var in2 = {
  "id": "185",
  "original_name": "United States",
  "country_id": "24",
  "article_id": "265"
}

var in3 = {
  "id": "73",
  "month": "July",
  "year": "1863",
  "suffix": "",
  "article_id": "265"
}

// construct a new object using the selected fields
// from each object in1, in2, or in3:
var out = {
  id: in1.id,
  title: in1.title,
  original_name: in2.original_name,
  year: in3.year
}

console.log(out);

If you have three lists of objects:

...in this case it's a lot more complicated (and a lot more interesting). In this case you would need to match fields from the objects in each list which share the same IDs.

The following is definitely not the most efficient or memory-conserving way to do this; I've spread things out to (hopefully) make it easier to follow what it's doing.

I'm making two assumptions:

  • within each list, all IDs are unique (meaning you won't have two objects with the same ID in one JSON file)
  • Every ID will appear in all three lists (meaning you don't need to handle missing fields in output)

/* Again handwaving past loading JSON strings and parsing
them into javascript objects, we'll just start with
three arrays: */

var input1 = [{
    "id": "265",
    "title": "Battle of Gettysburg",
    "page_id": "4849",
    "language_id": "en",
    "original_time": "July 1\u20133, 1863"
  },
  {
    "id": "1",
    "title": "Foo",
    "page_id": "123",
    "language_id": "en",
    "original_time": "July 1\u20133, 1863"
  }
];

var input2 = [{
    "id": "1",
    "original_name": "Bar",
    "country_id": "24",
    "article_id": "265"
  },
  {
    "id": "265",
    "original_name": "United States",
    "country_id": "24",
    "article_id": "265"
  }
]

var input3 = [{
    "id": "1",
    "month": "July",
    "year": "Baz",
    "suffix": "",
    "article_id": "265"
  },
  {
    "id": "265",
    "month": "July",
    "year": "1863",
    "suffix": "",
    "article_id": "265"
  }
]

/* It would be much easier to find corresponding IDs
across these arrays if they weren't arrays. We'll
start by converting them into objects keyed by the
item ids: */

var convertArray = function(arr) {
  var output = {};
  arr.forEach(function(o) {
    output[o.id] = o;
  });
  return output;
}

var obj1 = convertArray(input1);
var obj2 = convertArray(input2);
var obj3 = convertArray(input3);

/* Now if we need to find (say) the object with id "foo", we don't 
   need to search the whole array, but can just use `obj1["foo"]` or
   `obj1.foo`.  

   The last step is to iterate over the list of IDs and repeatedly 
   do basically the same thing as in the "if you have three objects"
   part above.  The only difference is that we need to access the
   object with the same ID in each of the input lists: */

var constructOutput = function(in1, in2, in3) {
  var output = []; // we'll be outputting a list of objects again.

  // step through every ID (assuming in1 contains all of them):
  Object.keys(in1).forEach(function(id) {
    var obj = {
      id: id,
      title: in1[id].title,
      original_name: in2[id].original_name,
      year: in3[id].year
    }
    output.push(obj);
  });
  return output;
}

var final = constructOutput(obj1, obj2, obj3)
console.log(final)
Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
1

Should you want to combine n number of JSON objects, e.g. a list of objects you can take a functional approach and utilise reduce + filter.

const data = [{
    "id":"265",
    "title":"Battle of Gettysburg",
    "page_id":"4849",
    "language_id":"en",
    "original_time":"July 1\u20133, 1863"
  },
  {
     "id":"185",
     "original_name":"United States",
     "country_id":"24",
     "article_id":"265"
  },
  {
    "id":"73",
     "month":"July",
     "year":"1863",
     "suffix":"",
     "article_id":"265"
  }];

const final = data.reduce((accu, { id, title }, index, array) => {
  // Find any related objects
  const matches = array.filter(data => data.article_id === id);

  if (matches.length) {
    // Flatten them for ease of access. Duplicate keys will override.
    const flat = matches.reduce((arr, item) => ({ ...arr, ...item }), [])

    // Return new object
    return accu.concat({
      ...flat,
      id,
      title,
    });
  }
  return accu;
}, []);

console.log(final, '<<')

// Witness
document.getElementById('results').innerHTML = JSON.stringify(final);
<div id="results" style="font-family: Courier; font-size 14px; color: #fff; background: #000; padding: 20px; max-width: 80vw;"></div>
Naz
  • 398
  • 2
  • 6
-1

Edited*

Maybe this is what you need?

let arrPages = [{  
   "id":"265",
   "title":"Battle of Gettysburg",
   "page_id":"4849",
   "language_id":"en",
   "original_time":"July 1\u20133, 1863"
}];

let arrArticles = [{  
   "id":"185",
   "original_name":"United States",
   "country_id":"24",
   "article_id":"265"
},
{  
   "id":"73",
   "month":"July",
   "year":"1863",
   "suffix":"",
   "article_id":"265"
}];

let getResult = (arrInput, arrCompare) => {
  let joinedItems = [];
  arrInput.forEach(item => {
    let newItem = { id: item.id, title: item.title };
    arrCompare.forEach(subItem => {
      if(subItem.article_id !== undefined && subItem.article_id === item.id){
        if(subItem.original_name !== undefined)
          newItem.original_name = subItem.original_name;
        if(subItem.year !== undefined)
          newItem.year = subItem.year;
      }
    });
    
  joinedItems.push(newItem);
  });
  
  return joinedItems;
};

let result = getResult(arrPages, arrArticles);

console.log(result);
iNovelletto
  • 227
  • 2
  • 4
  • 2
    This'll work but only for the specific data in the example - @rob.m suggests (in his comment) that the actual source is much larger than three separate blobs. Would recommend he moves this info into his question. – Naz May 29 '18 at 20:00
  • 1
    This doesn't cover the essential point of doing a JOIN based on `article_id = id`. – DavidW May 29 '18 at 20:01
  • @Naz yes will do. They are larger jsons. – rob.m May 29 '18 at 20:25
  • @rob.m check if this is what you need. Sorry for not getting your main problem – iNovelletto May 29 '18 at 20:37
-1

In the first part of the code i create a var that has the json data.
To solve the problema i create 2 functions, the order of the creation dosen't metter, the first function getJSONData() take the json data as parameter and return a object filtered by the keys defined in the array keys. The secound function just check if the current key is present in the array of keys, this function could be replaced by the jQuery.inArray() method.

// JSON data 
var json = [{  
       "id":"265",
       "title":"Battle of Gettysburg",
       "page_id":"4849",
       "language_id":"en",
       "original_time":"July 1\u20133, 1863"
    },
    {  
       "id":"185",
       "original_name":"United States",
       "country_id":"24",
       "article_id":"265"
    },
    {  
       "id":"73",
       "month":"July",
       "year":"1863",
       "suffix":"",
       "article_id":"265"
    }]

// keys that i want
var keys = ["title", "original_name", "year"];

// var that will have the filtered data
var newJSON = getJSONData(json);


console.log(JSON.stringify(newJSON))

// this is the main function of the code 
// here we iterate in the json creating a new object that has all the tags definid in the keys array
function getJSONData(arrayJSON){
  var JSONFiltered = {};
  for(var i in arrayJSON){
    for(var key in arrayJSON[i]){
      if(hasElement(key)){
        JSONFiltered[key] = arrayJSON[i][key];
      }
    }
  }
  return JSONFiltered;
}

// this function is used to check a key is present in the array of keys
function hasElement(key){
  for(var elem in keys){
    if(keys[elem] == key) return true;
  }
  return false;
}
Rafael Umbelino
  • 771
  • 7
  • 14
  • could you explain the last bit of your code? I see that is where you're checking for the match but why is it after the console.log? – rob.m May 29 '18 at 20:20
  • why did they put a down vote? Looks like it is working – rob.m May 29 '18 at 20:21
  • Why is this outputting an array of fieldnames mixed with values? – Daniel Beck May 29 '18 at 20:23
  • @DanielBeck true, I only need the values indeed – rob.m May 29 '18 at 20:23
  • we should simply do `newJSON.push(json[i][key]);` i guess – rob.m May 29 '18 at 20:27
  • yet we have an issue, since I need the `id` too, if I do `var keys = ["id", "title", "original_name", "year"];` it'll take the `id` from all the three objects while I only need the `id` form the first one – rob.m May 29 '18 at 20:33