Resolve References in JSON : Javascript / JSON - javascript

I have the following sample JSON coming from a server. Duplicate objects are being internally referred to by an id (see the JSON below).
[
{ "id": 1,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent#gmail.com"
},
{ "id": 2,
"agent": 1, // here I want the full object and not the Id
"user":"agent1#gmail.com"
}
]
Question:
How do I resolve the objects referred to in this fashion given a random JSON object?
(For instance, for the sample JSON above, I will have the below output:)
[
{ "id": 1,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent#gmail.com"
},
{ "id": 2,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent1#gmail.com"
}
]

Basically a single loop proposal, which collects unresolved links and if found the it replaces the open parts with the object.
var data = [{ "id": 1, "agent": { "id": 1, "firstName": "gghg", "lastName": "gh", "phone": "4543534", "admin": true }, "user": "agent#gmail.com" }, { "id": 2, "agent": 1, "user": "agent1#gmail.com" }];
data.forEach(function (a) {
if (typeof a.agent === 'object') {
this[a.agent.id] = this[a.agent.id] || {};
this[a.agent.id].data = a.agent;
this[a.agent.id].update && this[a.agent.id].update.forEach(function (b) {
b.agent = a.agent;
});
return;
}
this[a.agent] = this[a.agent] || {};
if (this[a.agent].data) {
a.agent = this[a.agent].data;
return;
}
this[a.agent].update = this[a.agent].update || [];
this[a.agent].update.push(a);
}, Object.create(null));
console.log(data);
Edit, a more generic version for unknown property references.
var data = [
{ id: 1, agent: { id: 1, firstName: "gghg", lastName: "gh", phone: "4543534", admin: true }, user: "agent#gmail.com", abc: 2 },
{ id: 2, agent: 1, user: "agent1#gmail.com", abc: { id: 2, text: 'blabla' } },
{ id: 3, agent: { id: 1, firstName: "gghg", lastName: "gh", phone: "4543534", admin: true }, user: "agent#gmail.com" },
];
data.forEach(function (a) {
Object.keys(a).forEach(function (k) {
if (typeof a[k] === 'object' && 'id' in a[k]) {
this[a[k].id] = this[a[k].id] || {};
this[a[k].id].data = a[k];
this[a[k].id].update && this[a[k].id].update.forEach(function (b) {
b[k] = a[k];
});
return;
}
this[a[k]] = this[a[k]] || {};
if (this[a[k]].data) {
a[k] = this[a[k]].data;
return;
}
this[a[k]].update = this[a[k]].update || [];
this[a[k]].update.push(a);
}, this);
}, Object.create(null));
console.log(data);

try this
var data = [
{ "id": 1,
"agent": {
"id": 1,
"firstName": "gghg",
"lastName": "gh",
"phone": "4543534",
"admin": true
},
"user":"agent#gmail.com"
},
{ "id": 2,
"agent": 1, // here I want the full object and not the Id
"user":"agent1#gmail.com"
}
];
var map = {};
//create a map of items by their id
data.forEach( function(obj){ map[ obj.id ] = obj.agent; } );
//iterate the data array and replace agents by their value if their value is a number.
data = data.map( function(obj){
if ( !isNaN( obj.agent ) )
{
obj.agent = JSON.parse( JSON.stringify( map[ obj.agent ] ) );
}
return obj;
});
console.log( data );

I think the only way is to run through the array two times:
UPD:
var arr = [ ... ]; // your list of data
var collectionFields = ['agent', 'someOtherField'];
var collections = {};
// collect all information about agents
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
for (var k = 0; k < collectionFields.length; k++) {
var field = collectionFields[k];
if (typeof collections[field] === 'undefined') {
collections[field] = {};
}
if (typeof item[field] === 'object') {
collections[field][item[field].id] = item[field];
}
}
}
for (var j = 0; j < arr.length; j++) {
for (var k = 0; k < collectionFields.length; k++) {
var field = collectionFields[k];
if (typeof arr[j][field] === 'number') {
arr[j][field] = collections[field][arr[j][field]];
}
}
console.log(arr);

var a = [ { "id": 1, "agent": {"id": 1, "firstName": "gghg", "lastName": "gh", "phone": "4543534",
"admin": true}, "user":"agent#gmail.com"},
{ "id": 2, "agent": 1, "user":"agent1#gmail.com"}];
//on = $.parseJSON(a);
console.log(a);
//nsole.log(bson);
var b=[];
var mapID = [];
for(var key in a) {
console.log(a[key].agent);
b[key] = a[key];
if($.isNumeric(a[key].agent)){
var id = a[key].agent;
b[key].agent = a[mapID[id]].agent;
}
mapID[a[key].id] = key;
}
console.log(b);
check working demo

You can simply define a getter for items which has only the agent ID.
var data = [{ "id": 1, "agent": { "id": 1, "firstName": "gghg", "lastName": "gh", "phone": "4543534", "admin": true }, "user": "agent#gmail.com" }, { "id": 2, "agent": 1, "user": "agent1#gmail.com" }];
console.clear();
data.forEach((hash => d => {
var agent = d.agent;
if (typeof agent === 'number')
Object.defineProperty(d, 'agent', {
get: () => hash[agent]
});
else
hash[agent.id] = agent;
})(Object.create(null)));
console.log(data);

Related

Push elements of

This is, I believe a very simple question for a JS programmer. Given the following array of objects named "categories"
[
{
"id": 1,
"name": "FURNITURE",
},
{
"id": 2,
"name": "AUTOMOTIVE",
},
{
"id": 3,
"name": "UPHOLSTERY",
}
]
I want to push the "name" on the "selectedCategories" array below where "id" === "id"
[
{
"id": 1
},
{
"id": 3
}
]
Below is my attempt to solve this, but ... not working..
for (let i = 0; i < selectedCategories.length; i++) {
for(let y = 0; y < categories.length; y++){
selectedCategories.name = categories[y].name
}
}
I believe this is what you are looking for
selectedCategories = selectedCategories.map(el => {
const searchEl = categories.find(e => e.id === el.id);
if (searchEl)
return { ...el, name: searchEl.name }
return el;
});
const categories = [
{
"id": 1,
"name": "FURNITURE",
},
{
"id": 2,
"name": "AUTOMOTIVE",
},
{
"id": 3,
"name": "UPHOLSTERY",
}
];
var selectedCategories = [
{
"id": 1,
},
{
"id": 3,
}
];
selectedCategories = selectedCategories.map(
selectedCategory => categories.find(category => category.id === selectedCategory.id),
);
console.log(selectedCategories);

Slicing an Array and producing an object from it

I have an array and it looks as follow:
[
{
"DT_RowId": "row_4758",
"companies": {
"id": 23,
"email": null,
"name": "test"
},
"USERS": {
"UserId": 23
}
},.....
]
How do I slice it and get only "companies": and the result as follows:
[
{
"id": 23,
"email": null,
"name": "test"
},.....
]
to clear some issues I have added the function in which I'm using data.map
fn.loadData = function (data) {
var dataKeys = Object.keys(data);
console.log(data)// 'data' is an object
console.log(data.map(x => x.companies)) ///data.map not a function error
var infiniteList = document.getElementById('infinite-list');
infiniteList.delegate = {
createItemContent: function (i) {
return ons._util.createElement(
'<ons-list-item modifier="chevron" tappable>' + data[dataKeys[i]].name + '</ons-list-item>'
);
},
countItems: function () {
return Object.keys(data).length;
}
};
infiniteList.refresh();
}
as comments told you to do:
const data = [
{
"DT_RowId": "row_4758",
"companies": {
"id": 23,
"email": null,
"name": "test"
},
"USERS": {
"UserId": 23
}
},
{
"DT_RowId": "row_3758",
"companies": {
"id": 24,
"email": null,
"name": "test3"
},
"USERS": {
"UserId": 24
}
},]
console.log(data.map(obj=>obj.companies))
This worked:
const newArray = [];
for (let i = 0; i < companyArray.length; i++) {
newArray.push(companyArray[i].companies);
}
Thanks, everyone

Normalize JSON to a custom schema

I have an array of objects with the following format
var arr = [
{
"productId": "123456",
"productName": "Test Product 1",
"description": [
"This is delicious",
"Suitable for vegetarian"
],
"attributes": {
"internalId": "091283"
"category": "Dairy"
},
"order": 1
}
];
And I am trying to map into something like below
[
[{
{
"name": "productId",
"value": "123456"
},
{
"name": "productName",
"value": "Test Product 1"
},
{
"name": "description",
"value": ["This is delicious", "Suitable for vegetarian"]
},
{
"name": "attributes",
"value": {
{
"name": "internalId",
"value": "091283"
},
{
"name": "category",
"value": "Dairy"
}
}
},
{
"name": "order",
"value": 1
}
}]
]
I tried mapping simple properties before going further and now stuck at getting only the last property of each object in the loop.
Suppose I don't know what are the format of incoming data and how can I normalize the JSON object to the format I want?
normalizeJson = (array) => {
for(i = 0; i < array.length; i++){
normalizedJson[i] = {};
Object.keys(array[i]).forEach(key => {
if (array[i][key] && typeof array[i][key] === "object") {
// normalizeJson(obj[key]);
// console.log(key + ' is object');
return;
} else {
o = {};
o["name"] = key;
o["value"] = array[i][key];
normalizedJson[i] = o;
// normalizedJson[i]["name"] = key;
// normalizedJson[i].value = array[i][key];
// console.log(key);
return;
}
});
}
console.log(normalizedJson);
};
Or is there any library I can use in order to achieve this?
Try this
var obj = [
{
productId: "123456",
productName: "Test Product 1",
description: ["This is delicious", "Suitable for vegetarian"],
attributes: {
internalId: "091283",
category: "Dairy",
},
order: 1,
},
];
function normalizeObject(obj) {
var result = [];
if (Array.isArray(obj)) {
for (let i of obj) {
result.push(normalizeObject(i));
}
} else if (typeof obj == "object") {
for (let i of Object.keys(obj)) {
result.push({ name: i, value: normalizeObject(obj[i]) });
}
} else {
return obj;
}
return result;
}
console.log(JSON.stringify(normalizeObject(obj), null, 2));
This looping method called recursion. Which is loop by calling function itself.

Find the latter date in an object

I need iterate specific objects in an object, and find the object with latter Date.
Here is example of my object:
var o = {
"data": [
{
"id": 2,
"category": "test1",
"parents": [
{
"id": 31,
"children": [
{
"firstName": "Steve",
"lastName": "Martin",
"created": "2018-04-06T22:00:00.000Z"
},
{
"firstName": "Steve2",
"lastName": "Martin2",
"created": "2016-02-10T23:00:00.000Z"
}
]
},
{
"id": 31,
"children": [
{
"firstName": "Julia",
"lastName": "Robbery",
"created": "2015-01-06T23:00:00.000Z"
},
{
"firstName": "Nikol",
"lastName": "Surachenko",
"created": "2017-04-06T22:00:00.000Z"
},
{
"firstName": "Nikol",
"lastName": "Surachenko",
"created": "2011-06-05T22:00:00.000Z"
}
]
}
]
}
]
}
I tried this:
var latter = null;
for (var i = 0; i < o.data[0].parents.length; i++) {
for (var j = 0; j < o.data[0].parents[i].children.length; j++) {
if (latter == null || moment(latter) < moment(o.data[0].parents[i].children[j].created))
latter=o.data[0].parents[i].children[j].created;
}
}
Can you tell me if exist some prettier way? For example with lambda, etc.?
Thanks in advice.
"pretty" is subjective, but in my opinion with lodash you could write it in a bit cleaner way:
mostRecent = _.max(
_.flatMap(
_.get(o, 'data.0.parents'),
'children'),
'created')
If lodash is not an option, you can roll out your own ad-hoc microframework:
let get = p => o => o[p];
let flatMap = (a, f) => [].concat(...a.map(f));
let max = (a, f) => a.map(x => [x, f(x)]).reduce((m, p) => m[1] > p[1] ? m : p)[0];
mostRecent = max(
flatMap(o.data[0].parents, get('children')),
get('created')
)
Using for-loops and compare dates.
This approach downstreams into the whole object to get the right object.
var o = { "data": [{ "id": 2, "category": "test1", "parents": [{ "id": 31, "children": [{ "firstName": "Steve", "lastName": "Martin", "created": "2018-04-06T22:00:00.000Z" }, { "firstName": "Steve2", "lastName": "Martin2", "created": "2016-02-10T23:00:00.000Z" } ] }, { "id": 31, "children": [{ "firstName": "Julia", "lastName": "Robbery", "created": "2015-01-06T23:00:00.000Z" }, { "firstName": "Nikol", "lastName": "Surachenko", "created": "2017-04-06T22:00:00.000Z" }, { "firstName": "Nikol", "lastName": "Surachenko", "created": "2011-06-05T22:00:00.000Z" } ] } ] }] }
var result = {};
for (var obj of o.data) {
for (var p of obj.parents) {
for (var c of p.children) {
result = !result.created || Date.parse(c.created) > Date.parse(result.created) ? c : result;
}
}
}
console.log(result);
You might do it a bit more functional:
const result = o.data[0].parents.reduce((res, {children}) => res.concat(children), [])
.reduce((old, curr) => Date(old.created) > Date(curr.created) ? old : curr);

data transformation from one form of array to another

I have doubt about data structure transformation from one form of array to another.
My input data is of the form,
var testVar=[
{
"count": 1,
"term": "Company",
"Company": [
{
"Tata": [
{
"count": 1,
"term": "Tatagroup"
}
],
"sector": "Automotive",
"type": "Car"
},
]
},
{
"count": 2,
"term": "Country",
"Country": [
{
"France": [
{
"count": 1,
"term": "France"
}
],
"region": "Europe",
"Player": "Zidane",
"term": "France",
"code": "FRA"
},
{
"region": "Europe",
"Player": "Federer",
"term": "Switzerland",
"Switzerland": [
{
"count": 1,
"term": "Switzerland"
}
],
"code": "SWI"
}
]
}];
and I am trying to transform it to the form,
[ "Tata" : [{"sector" : "automotive"}, "type" : "car"], "France": [{"region" : "Europe}, {"Player" : "Zidane"} , {"code" : "FRA"}], "switzerland" : [{"region" : "Europe}, {"Player" : "Federer"} , {"code" : "SWI"}]];
The code I came up with looks like http://jsfiddle.net/X2apw/2/, bt its nt accurate..
var testvar = [...];
var result = {};
for (var i=0; i<testvar.length; i++) {
var arr = testvar[i][testvar[i].term];
for (var j=0; j<arr.length; j++) {
var resarr = [];
for (var k in arr[j]) {
if (typeof arr[j][k] == "string") {
var obj = {};
obj[k] = arr[j][k];
resarr.push(obj);
} else {
result[k] = resarr;
}
}
}
}
(Demo at jsfiddle.net)
However, I strongly recommend to use just one object instead of an array of one-property-objects in your result format. Change the inner loop body to:
var resobj = {};
for (var k in arr[j]) {
if (typeof arr[j][k] == "string") {
resobj[k] = arr[j][k];
} else {
result[k] = resobj;
}
}
(Demo)

Categories