Merging two json array object based on union and intersection - javascript

I am trying to merge two json array with objects as element. You may refer to this plunkr file for both json. I have succesfully retrieve the expected final outcome array id, but I do not know how to form back the expected json as below. I am using underscore js for this purpose.
Note: If object exist in newJson and not in currentJson, after merge, it will be inactive state by default.
I am not sure whether I am using the correct approach. This is what I have try:
var newJsonID = _.pluck(newJson, 'id');
var currentJsonID = _.pluck(currentJson, 'id');
var union = _.union(newJsonID, currentJsonID);
var intersection = _.intersection(currentJsonID, newJsonID);
var final = _.difference(union, _.difference( currentJsonID, intersection);
Expected Final Outcome:
[
{
"id": "12",
"property1Name": "1"
"status": "inactive"
},
{
"id": "11",
"property1Name": "1"
"status": "inactive"
},
{
"id": "10",
"property1Name": "1"
"status": "inactive"
},
{
"id": "9",
"property1Name": "1"
"status": "active"
}
]

A solution in plain Javascript with two loops and a hash table for lookup.
function update(newArray, currentArray) {
var hash = Object.create(null);
currentArray.forEach(function (a) {
hash[a.id] = a.status;
});
newArray.forEach(function (a) {
a.status = hash[a.id] || 'inactive';
});
}
var newJson = [{ "id": "12", "property1Name": "1" }, { "id": "11", "property1Name": "1" }, { "id": "10", "property1Name": "1" }, { "id": "9", "property1Name": "1" }],
currentJson = [{ "id": "10", "property1Name": "1", "status": "inactive" }, { "id": "9", "property1Name": "1", "status": "active" }, { "id": "8", "property1Name": "1", "status": "active" }, { "id": "7", "property1Name": "1", "status": "inactive" }];
update(newJson, currentJson);
document.write('<pre>' + JSON.stringify(newJson, 0, 4) + '</pre>');

Related

Find element in array of x depth Javascript

Is it possible to use the find() method within an array of depth x?
For example, suppose I have the following array of objects, call it test:
[
{
"id": "1",
"title": "First",
},
{
"id": "2",
"title": "Second",
"movies": [
{
"id": "3",
"title": "Happy Gilmore",
"Actors": [
{
"id": "4",
"title": "John Doe",
},
{
"id": "5",
"title": "Jane Doe",
},
],
"Producers": [
{
"id": "6",
"title": "Max Smith",
},
{
"id": "7",
"title": "Richard Rocky",
},
],
},
{
"id": "10",
"title": "Billy Madison",
"Actors": [
{
"id": "40",
"title": "John Smith",
},
{
"id": "50",
"title": "Alex Doe",
},
],
"Producers": [
{
"id": "60",
"title": "Bob Smith",
},
{
"id": "70",
"title": "Polly Rocky",
},
],
}
]
}
]
Suppose I am looking for the "2" id. I can use the find() method to search the first level of the array and return the desired object by doing test.find(element => element.id === "2").
However, suppose I am now looking for the occurrence where the id is 4. As you can see from the above JSON, that element is within a sub array within test. Is there a way therefore where I can still search through test to find the element where id=4?
find cannot do this, but you can use it in a recursive approach:
function findDeep(arr, predicate) {
let res = arr.find(predicate);
if (res !== undefined) return res;
for (let obj of arr) {
for (let value of Object.values(Object(obj)).filter(Array.isArray)) {
res = findDeep(value, predicate);
if (res !== undefined) return res;
}
}
}
let test = [{"id": "1","title": "First",},{"id": "2","title": "Second","movies": [{"id": "3","title": "Happy Gilmore","Actors": [{"id": "4","title": "John Doe",},{"id": "5","title": "Jane Doe",},],"Producers": [{"id": "6","title": "Max Smith",},{"id": "7","title": "Richard Rocky",},],},{"id": "10","title": "Billy Madison","Actors": [{"id": "40","title": "John Smith",},{"id": "50","title": "Alex Doe",},],"Producers": [{"id": "60","title": "Bob Smith",},{"id": "70","title": "Polly Rocky",},],}]}];
let res = findDeep(test, obj => obj.id == "4");
console.log(res);

How can I concatenate this type of JSON in javascript?

How can I concatenate this json to obtain it:
complements = ["XYZ 3, CDE TR, AAA 5", "", "NDP 3, DDD FR"] ?
Each address can contain a set of complements which must be concatenated and separated by a comma.
P.s: I'm using javascript.
P.s2: Complements can be null like in the second group in JSON.
[
{
"postalcode": "1234",
"street": "ABC",
"number": "1",
"complement": [
{
"type": "B",
"name": "XYZ",
"description": "3"
},
{
"type": "C",
"name": "CDE",
"description": "TR"
},
{
"type": "D",
"name": "AAA",
"description": "5"
}
]
},
{
"postalcode": "444",
"street": "No complements",
"number": "5"
},
{
"postalcode": "2222",
"street": "BBB",
"number": "2",
"complement": [
{
"type": "E",
"name": "NDP",
"description": "3"
},
{
"type": "F",
"name": "DDD",
"description": "FR"
}
]
}
];
My code I'm getting this.complementsList.forEach is not a function.
getComplement(addressesResponse){
this.complementsList = JSON.parse(addressesResponse);
this.complementsList.forEach((item) => {
Object.defineProperty(item, 'complements', {
get: function() {
return this.complement.map((c) => `${c.name} ${c.description}`).join(', '); }
})
});
Source: https://salesforce.stackexchange.com/questions/367713/how-to-render-a-json-in-the-same-line-lwc
how i solved it :
arr.map((x)=>x.complement != null? (x.complement.map((y)=>y.name+' '+y.description)+"") :'');
Having a javascript object, you can go through the keys of the object and combine some of them into strings
It will look something like this:
const jsonObject = [{...}, {...}, ...]
const complements = [];
jsonObject.forEach((item) => {
let complement = item['complement'].reduce((result, currObj)
=> result += (currObj.name+' '+currObj.description), "");
complements.push(complement);
});
This is just an example. There are many ways to do it.

How to get the corresponding value from two objects

I have first data object which has a list of cafe, and second data object which has a list of cafe types.
I need find, get and display the corresponding type value from first data object and ID value from second data object.
For example: in list of cafe, I have Pinta with "type" : "3", it means that 3 is Bar from second object.
First object:
{
"list": {
"item": [
{
"ID": "31",
"name": "Staut",
"type": "1",
},
{
"ID": "34",
"name": "Pinta",
"type": "3",
}
]
}
}
And second object:
{
"list": {
"item": [
{
"ID": "1",
"name": "Restaurant",
},
{
"ID": "2",
"name": "Cafe",
},
{
"ID": "3",
"name": "Bar",
}
]
}
}
I can do it with Lodash. It is right, but I can't display it and it uses high memory.
getValues: function() {
_.forEach(CafeJSON.list.item, function(cafeValue) {
_.forEach(TypeJSON.list.item, function(typeValue){
if (cafeValue.type == typeValue.ID) {
console.log("Cafe name is: ", cafeValue.name, "and type is: ", typeValue.name)
}
})
})
}
Result:
I'd simplify the types object down to a object having key value pairs in the form of '3': 'Bar', then loop the items once, overriding the type property's value.
let list = {
"list": {
"item": [{
"ID": "31",
"name": "Staut",
"type": "1",
},
{
"ID": "34",
"name": "Pinta",
"type": "3",
}
]
}
}
let types = {
"list": {
"item": [{
"ID": "1",
"name": "Restaurant",
},
{
"ID": "2",
"name": "Cafe",
},
{
"ID": "3",
"name": "Bar",
}
]
}
}
let typesSimplified = types.list.item.reduce((a, b) => {
a[b.ID] = b.name;
return a;
}, {});
list.list.item.forEach(e => {
e.type = typesSimplified[e.type];
});
console.log(list);

How to filter data of an object array with lodash

var brands = [];
brands = [null, {
"id": "1",
"image": "/images/brands/surf_excel.png",
"name": "Surf Excel",
"productCount": "6"
}, {
"id": "2",
"image": "/images/brands/rin.png",
"name": "Rin",
"productCount": "5"
}, {
"id": "3",
"image": "/images/brands/ariel.png",
"name": "Ariel",
"productCount": "4"
}];
Now i want to get the name where id = 3. I tried
var data = _.filter(brands, { 'id': 3 });
console.log(data.name);
But its giving error can't read property of undefined. Assuing there will be only one record for id =3, Can anyne help me on this. How to get name from given id in the above structure.
If there is any better way to get the same result that is also appreciated.
As you have specified lodash and using it's _.filter() method. You can use pass predicate which can a function which will be invoke per iteration. As note it will return you an array.
var data = _.filter(brands, function(brand){
return brand != null && brand.id == 3;
});
console.log(data[0].name);
if you want only one element the use _.find()
var data = _.find(brands, function(brand){
return brand != null && brand.id == 3;
});
console.log(data.name);
Use native JavaScript Array#find method.
var brands = [];
brands = [null, {
"id": "1",
"image": "/images/brands/surf_excel.png",
"name": "Surf Excel",
"productCount": "6"
}, {
"id": "2",
"image": "/images/brands/rin.png",
"name": "Rin",
"productCount": "5"
}, {
"id": "3",
"image": "/images/brands/ariel.png",
"name": "Ariel",
"productCount": "4"
}];
var data = brands.find(function(v) {
return v && v.id == "3";
});
console.log(data.name);
Check polyfill option for find method for older browser.
If you want to filter out the array then use Array#filter method.
var brands = [];
brands = [null, {
"id": "1",
"image": "/images/brands/surf_excel.png",
"name": "Surf Excel",
"productCount": "6"
}, {
"id": "2",
"image": "/images/brands/rin.png",
"name": "Rin",
"productCount": "5"
}, {
"id": "3",
"image": "/images/brands/ariel.png",
"name": "Ariel",
"productCount": "4"
}];
var data = brands.filter(function(v) {
return v && v.id == "3";
});
console.log(data[0].name);
UPDATE :
You are provided an object as the second argument as per documentation which uses _.matches for property value comparison. In your array id property holds a string value but you were provided as a number in the filter just change it to string will make it work or use callback function as in #Satpal answer.
var brands = [];
brands = [null, {
"id": "1",
"image": "/images/brands/surf_excel.png",
"name": "Surf Excel",
"productCount": "6"
}, {
"id": "2",
"image": "/images/brands/rin.png",
"name": "Rin",
"productCount": "5"
}, {
"id": "3",
"image": "/images/brands/ariel.png",
"name": "Ariel",
"productCount": "4"
}];
var data = _.filter(brands, {
'id': "3"
});
console.log(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>
Aside from using filter() instead of find(), you're actually pretty close. The reason you're not seeing any results is because the object predicates that you can pass to find()/filter() perform strict equality comparisons. Meaning, 3 === '3' will evaluate to false.

sort and pattern match an json

Am having a json like below,
[
{
"id": "1",
"freq": "1",
"value": "Tiruchengode",
"label": "Tiruchengode"
},
{
"id": "2",
"freq": "1",
"value": "Coimbatore",
"label": "Coimbatore"
},
{
"id": "3",
"freq": "1",
"value": "Erode",
"label": "Erode"
},
{
"id": "4",
"freq": "1",
"value": "Madurai",
"label": "Madurai"
},
{
"id": "5",
"freq": "1",
"value": "Salem",
"label": "Salem"
},
{
"id": "6",
"freq": "1",
"value": "Tiruchirappalli",
"label": "Tiruchirappalli"
},
{
"id": "7",
"freq": "1",
"value": "Tirunelveli",
"label": "Tirunelveli"
}
]
I need to pattern match it with label item in this json (ie), If I type tiru, then it has to result label items having tiru substrings in it.If its a single item array I know how to pattern match and sort it. Here am completely unaware that, how to pattern match using label item in the array. Is it possible to?. I need to do with Pure javascript, any help guys?
You can use the functional array methods introduced in JavaScript 1.6, specifically filter:
var search = 'tiru';
var results = obj.filter(function(item) {
var a = item.label.toUpperCase();
var b = search.toUpperCase();
return a.indexOf(b) >= 0;
});
If you wanted labels only, you can then use map to return only that property alone:
var labels = obj.filter(function(item) {
var a = item.label.toUpperCase();
var b = search.toUpperCase();
return a.indexOf(b) >= 0;
}).map(function(item) {
return item.label;
});
Essentially, filter is a method available to any Array which returns a new Array containing only those members for which the supplied function return true.
JSON.parse() will help convert the jsonString to JsonObject then just iterate the object use indexOf for pattern matching.
var jsonString = '[{"id": "1","freq": "1","value": "Tiruchengode","label": "Tiruchengode"},{"id": "2","freq": "1","value": "Coimbatore","label": "Coimbatore"},{"id": "3","freq": "1","value": "Erode","label": "Erode"},{"id": "4","freq": "1","value": "Madurai","label": "Madurai"},{"id": "5","freq": "1","value": "Salem","label": "Salem"},{"id": "6","freq": "1","value": "Tiruchirappalli","label": "Tiruchirappalli"},{"id": "7","freq": "1","value": "Tirunelveli","label": "Tirunelveli"}]';
var jsonObjects = JSON.parse(jsonString);
var pattern = "tiru";
for(var key in jsonObjects){
var label = jsonObjects[key].label.toUpperCase();
if(label.indexOf(pattern.toUpperCase()) != -1){
document.write(label+"<br/>");
}
}

Categories