Merge two objects when there's a new key - javascript

I have two objects with the following structure and tried to merge them together.
I tried it with $.merge but its not the expected result.
Object 1 - Has not all attributes
{
"id": 23,
"name": "Article",
"related": 15 "items": [{
"name": "Test1",
"items": [{
"name": "Test2",
"items": [{
"name": "Test3",
"items": [{
"name": "Test4",
"items": [{
"name": "Test5",
"items": [{
"name": "Test6",
}]
}]
}]
}]
}]
}]
}, {
"id": 24…
}
Object 2 - with additional attributes
{
"id": 23,
"name": "Article",
"related": 15 "items": [{
"name": "Test1",
"id": 34 "items": [{
"name": "Test2",
"id": 57 "items": [{
"name": "Test3",
"id": 92 "items": [{
"name": "THIS ONE IS NOT EXISTING IN OBJECT 1 AND SHOULD NOT GET MERGED",
"id": 789
}, {
"name": "Test4",
"id": 12 "items": [{
"name": "Test5",
"id": 321 "items": [{
"name": "Test6",
"id": 285
}]
}]
}]
}]
}]
}]
}, {
"id": 24…
}
Does anyone know some smart trick? Is jQuery even necessary?

jQuery's $.extend will do what you want.
//merging two objects into new object
var new_object = $.extend(true, {}, object1, object2);
//merge object2 into object1
$.extend(true, object1, object2);
The 1st parameter: deep:true, see: https://api.jquery.com/jquery.extend/

Without jquery: https://jsfiddle.net/sLhcbewh/
function mymerge_sub(object1, object2)
{
for(var i in object2) {
if(i == 'items')
continue;
console.log(i);
if(object1[i] === undefined) {
console.log(i + ' not found');
object1[i] = object2[i];
}
}
if(object1.items !== undefined) {
mymerge_sub(object1.items[0], object2.items[0])
}
}
function mymerge(object1, object2) {
var ret = JSON.parse(JSON.stringify(object1));
mymerge_sub(ret, object2); // save obj 1
return ret;
}
var obj3 = mymerge(obj1, obj2);
If you want several items, you have to loop mymerge_sub(object1.items[j]... ).

Related

how to update a deeply nested object in Javascript?

I have a this type of a json object.
{
"id": "001",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
},
{
"id": "003",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003"],
"children": [
{
"id": "00001",
"type": "B",
"children": []
}
]
},
{
"id": "004",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004"],
"children": [
{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": []
},{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": [
{
"id": "00002",
"type": "B",
"children": []
}
]
}
]
},
{
"id": "00003",
"type": "B",
"children": []
}
]
}
I need to replace all the object which is type: "B" , with this (which is mentioned below) type of object which I can get from an object with ids as keys of typed B. This typed B objects can be nested anywhere either as a first child or fifth child of a nested arrays of children
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"children": []
},
How can I do that? This can be deeply nested and there's no specific place where we should replace the objects, beforehand. So, I need to go through the entire object and do that. How should I get it done?
EDIT
I updated the code in the question slightly. There's a path property of the nested in each object, except for typed B objects. So, when replacing the typed B properties with the other object, I need to add the paths in there as well.
eg: path for id: "00001", typed B object should be : ["001", "003", "00001"]
EDIT :
Expected result
{
"id": "001",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
},
{
"id": "003",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003", "002"],
"children": []
},
]
},
{
"id": "004",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004"],
"children": [
{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": []
},{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005", "002"],
"children": []
}
]
}
]
},
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
}
]
}
lodash if you don't mind.
Use cloneDeepWith to clone the entire tree and replace a specific value.
const data = {"id":"001","type":"A","value":"aaaaa","data:":{},"children":[{"id":"002","type":"A","value":"aaaaa","data:":{},"children":[]},{"id":"003","type":"A","value":"aaaaa","data:":{},"children":[{"id":"00001","type":"B","children":[]}]},{"id":"004","type":"A","value":"aaaaa","data:":{},"children":[{"id":"005","type":"A","value":"aaaaa","data:":{},"children":[]},{"id":"005","type":"A","value":"aaaaa","data:":{},"children":[{"id":"00002","type":"B","children":[]}]}]},{"id":"00003","type":"B","children":[]}]};
const result = _.cloneDeepWith(data, (value) => {
const newObj = {"id": "002", "type": "A", "value": "---NEW VALUE FOR 'B' TYPE---", "data:": {} };
return (value.type === 'B') ? { ...value, ...newObj} : _.noop();
});
console.dir(result, { depth: null } );
.as-console-wrapper{min-height: 100%!important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js" integrity="sha512-2iwCHjuj+PmdCyvb88rMOch0UcKQxVHi/gsAml1fN3eg82IDaO/cdzzeXX4iF2VzIIes7pODE1/G0ts3QBwslA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
--- Update 2--- (Without lodash)
Use local variable to store and combine current path.
const data = { "id": "001", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001"], "children": [{ "id": "002", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "002"], "children": [] }, { "id": "003", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "003"], "children": [{ "id": "00001", "type": "B", "children": [] }] }, { "id": "004", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004"], "children": [{ "id": "005", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004", "005"], "children": [] }, { "id": "005", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004", "005"], "children": [{ "id": "00002", "type": "B", "children": [] }] }] }, { "id": "00003", "type": "B", "children": [] }] }
const deepReplace = (obj, prevPath = []) => {
if (obj.type === 'A') {
if (obj.children.length) {
obj.children = obj.children.map((childObj) => deepReplace(childObj, obj.path))
}
return obj;
};
if (obj.type === 'B') {
const id = '002';
return { id, type: "A", value: "aaaaa", path: [...prevPath, id], data: {}, children: []};
};
};
console.dir(deepReplace(data), { depth: null });
.as-console-wrapper{min-height: 100%!important; top: 0}
This looks like a tree traversal problem. Here's a way to handle that with depth-first search without recursion.
As mentioned in this answer, recursion should be avoided whenever possible, as it requires more memory and is more difficult to debug than an iterative implementation.
Updated per adjustment in question
const data = {"id":"001","type":"A","value":"aaaaa","data:":{},"path":["001"],"children":[{"id":"002","type":"A","value":"aaaaa","data:":{},"path":["001","002"],"children":[]},{"id":"003","type":"A","value":"aaaaa","data:":{},"path":["001","003"],"children":[{"id":"00001","type":"B","children":[]}]},{"id":"004","type":"A","value":"aaaaa","data:":{},"path":["001","004"],"children":[{"id":"005","type":"A","value":"aaaaa","data:":{},"path":["001","004","005"],"children":[]},{"id":"005","type":"A","value":"aaaaa","data:":{},"path":["001","004","005"],"children":[{"id":"00002","type":"B","children":[]}]}]},{"id":"00003","type":"B","children":[]}]};
const dfs = () => {
const stack = [[data, null]];
while(stack.length) {
const [curr, parent] = stack.pop();
// check for match on type
if (curr.type === "B") {
curr.type = "A";
curr.id = "002";
curr.value = "aaaaa";
curr.data = {};
curr.path = [...parent?.path.slice() ?? [], "002"];
}
curr.children.forEach(child => stack.push([child, curr]));
}
};
dfs();
const output = document.getElementById("output");
output.innerText = JSON.stringify(data, null, 2);
<pre id="output" />
I played around with this in the console and it did what you wanted (based on the json array provided, setting all the "B" to "A" types). It's a recursive function so on any nested child it meets in the "children" array it would call the function again on each item in the array.
function fixObjects (obj) {
if (obj["type"] === "B") {
obj["type"] = "A";
obj["id"] = "002";
obj["value"] = "aaaaa";
obj["data"] = {};
}
if (obj["children"].length > 0) {
obj["children"].forEach (child => fixObjects (child));
}
}
fixObjects (_yourArray)

map two array of object by common value js

const object1: [{
"code": "lap-143240121",
"index": 0
}, {
"code": "lap-15040293",
"index": 1
}, {
"code": "lp-1504444",
"index": 2
}, {
"code": "lp-150440987",
"index": 3
}]
const object2: [{
"code": "lap-143240121",
"name": "name1"
}, {
"code": "lap-15040293",
"name": "name2"
}, {
"code": "lp-1504444",
"name": "name3"
}]
I would like to map those two list of object by code to have an output like :
const objectResult: [{
"code": "lap-143240121",
"index": 0,
"name": "name1"
}, {
"code": "lap-15040293",
"index": 1,
"name": "name2"
}, {
"code": "lp-1504444",
"index": 2,
"name": "name3"
}]
Use map to iterate object2 and then use rest operator to return an object which consist of all the elements and the name from object1
const object1 = [{
"code": "lap-143240121",
"index": 0
}, {
"code": "lap-15040293",
"index": 1
}, {
"code": "lp-1504444",
"index": 2
}, {
"code": "lp-150440987",
"index": 3
}]
const object2 = [{
"code": "lap-143240121",
"name": "name1"
}, {
"code": "lap-15040293",
"name": "name2"
}, {
"code": "lp-1504444",
"name": "name3"
}];
const obj3 = object2.map((item) => {
return {
...item, // will consist all the items from object2
// get index from object1 where the code matches
index: object1.find(elem => elem.code === item.code).index
}
});
console.log(obj3)
transform the object1 to Map with value of code as key and whole object as value
iterate on object2 search code from object2 in the above created map, if found merge the properties

how to compare the key in the array of object and modify it using javascript

I have two objects obj1 and obj2, how to loop through array key children and if code name matches, then add the name key in the object obj2, get the object.
How to loop through object of objects and match the key and push the key to get the new object in javascript
function newObject(obj1, obj2) {
var result = obj1.map(e => {
if ('children' in e)
e.children = e.children.map(child => {
if ('children' in child)
child.children = child.children.map(c => {
name: c.name
});
return child;
});
return e;
})
return result
}
var obj1 = [{
"id": 1,
"item": "node1",
"children": [{
"id": 2,
"code": "countries",
"title": "Country",
"children": [{
"cid": 12,
"code": "S1",
"name": "SG",
"children": [{
"id": 4,
"code": "C1",
"name": "City"
}]
},
{
"cid": 13,
"code": "S2",
"name": "TH"
}
]
},
{
"id": 2,
"code": "Groceries",
"title": "Grocery",
"children": [{
"cid": 11,
"code": "G1",
"name": "Fruits"
},
{
"cid": 10,
"code": "G2",
"name": "Vegetables"
}
]
}, {
"id": 3,
"code": "lists",
"title": "Option"
}
]
}];
var obj2 = [{
id: 1,
code: "G1",
status: "active"
},
{
id: 2,
code: "S2",
status: "inactive"
},
{
id: 3,
code: "C1",
status: "active"
}
];
console.log(this.newObject(obj1, obj2));
Expected Output
[
{id:1, name: "Fruits",code:"G1", status:"active"},
{id:2, name: "TH",code:"S2", status:"inactive"},
{id:3, name: "city",code:"C1", status:"active"}
]
you can check this code
I fixed your object and you can find your expectation in the console

Convert object to another object using jQuery

I am getting a result in my JavaScript file which I want to convert into another object.
My original result
[
{
"SName": "Set1",
"Elements": [
{
"Id": "3",
"Name": "Name1"
},
{
"Id": "5",
"Name": "Name2"
}
]
},
{
"SName": "Set2",
"Elements": [
{
"Id": "7",
"Name": "Name3"
},
{
"Id": "8",
"Name": "Name4"
}
]
}
]
Convert this to look like array of objects using jQuery or JavaScript. How can I achieve this?
[
{
"SName": "Set1",
"Id": 3,
"Name": "Name1"
},
{
"SName": "Set1",
"Id": 5,
"Name": "Name2"
},
{
"SName": "Set2",
"Id": 7,
"Name": "Name3"
},
{
"SName": "Set2",
"Id": 8,
"Name": "Name4"
}
]
var data = [
{
"SName": "Set1",
"Elements": [
{
"Id": "3",
"Name": "Name1"
},
{
"Id": "5",
"Name": "Name2"
}
]
},
{
"SName": "Set2",
"Elements": [
{
"Id": "7",
"Name": "Name3"
},
{
"Id": "8",
"Name": "Name4"
}
]
}
];
console.log(data);
var newData = data.reduce(function (newArray, currentSet) {
return newArray.concat(currentSet.Elements.map(function (element) {
return Object.assign( { SName: currentSet.SName }, element);
}));
}, []);
console.log(newData);
The key here is the reduce function. What we are doing is creating a brand new array, by looping through each value of the outer array. We continuously concatenate onto our new array with the values we map from the inner array.
You could iterate the array, the Elements and the properties and build a new object and push it to the result set.
var array = [{ "SName": "Set1", "Elements": [{ "Id": "3", "Name": "Name1" }, { "Id": "5", "Name": "Name2" }] }, { "SName": "Set2", "Elements": [{ "Id": "7", "Name": "Name3" }, { "Id": "8", "Name": "Name4" }] }],
result = [];
array.forEach(function (a) {
a.Elements.forEach(function (b) {
var o = { SName: a.SName };
Object.keys(b).forEach(function (k) {
o[k] = b[k];
});
result.push(o);
});
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6
var array = [{ "SName": "Set1", "Elements": [{ "Id": "3", "Name": "Name1" }, { "Id": "5", "Name": "Name2" }] }, { "SName": "Set2", "Elements": [{ "Id": "7", "Name": "Name3" }, { "Id": "8", "Name": "Name4" }] }],
result = [];
array.forEach(a => a.Elements.forEach(b => result.push(Object.assign({ SName: a.SName }, b))));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do this with reduce(), forEach() and Object.assign()
var data = [{
"SName": "Set1",
"Elements": [{
"Id": "3",
"Name": "Name1"
}, {
"Id": "5",
"Name": "Name2"
}]
}, {
"SName": "Set2",
"Elements": [{
"Id": "7",
"Name": "Name3"
}, {
"Id": "8",
"Name": "Name4"
}]
}]
var result = data.reduce(function(r, e) {
e.Elements.forEach(function(o) {
r.push(Object.assign({SName: e.SName}, o))
})
return r;
}, [])
console.log(result)
Here is solution using jQuery, here is jsfiddle:
https://jsfiddle.net/noitse/3uk9qjnf/
I hope you know all key names so it wont be problem to do it fixed.
var json = [
{
"SName": "Set1",
"Elements": [
{
"Id": "3",
"Name": "Name1"
},
{
"Id": "5",
"Name": "Name2"
}
]
},
{
"SName": "Set2",
"Elements": [
{
"Id": "7",
"Name": "Name3"
},
{
"Id": "8",
"Name": "Name4"
}
]
}
]
var newJSON = []
$(json).each(function(index,value){
$(value.Elements).each(function(index1,value1){
newJSON.push({"SName":value.SName,"Id":value1.Id,"Name":value1.Name})
})
})
alert(JSON.stringify(newJSON))
Here is code , what it does it loops through first JSON , then loops through its elements , then it push it to new array
You could use the $.extend method, which lets you create a copy of an object, while merging with another object.
var source = [] // Replace with the initalization of your source array
var destination = [];
for (var i = 0; i < source.length; i++) {
var node = source[i];
for (var j = 0; j < node.Elements.length; j++) {
var subNode = node.Elements[j];
newNode = $.extend(subNode, node);
delete newNode["Elements"];
destination.push(newNode);
}
}
You can run the code in this fiddle.

mongodb getting the oldest of animals map/reduce

I've never tried map/reduce.
How would I get the oldest of each type of animal?
My data is like this:
[
{
"cateory": "animal",
"type": "cat",
"age": 4,
"id": "a"
},
{
"cateory": "animal",
"type": "bird",
"age": 3,
"id": "b"
},
{
"cateory": "animal",
"type": "cat",
"age": 7
"id": "c"
},
{
"cateory": "animal",
"type": "bird",
"age": 4,
"id": "d"
},
{
"cateory": "animal",
"type": "cat",
"age": 8,
"id": "e"
},
{
"cateory": "company",
"type": "Internet",
"age": 5,
"id": "Facebook"
}
]
I'm using node-mongodb-native. Thanks!
Your map function should look something like this:
map = function() {
emit({type: this.type}, {age: this.age});
}
And the reduce function:
reduce = function(key, values) {
maxAge = 0;
values.forEach(function(v) {
if (maxAge < v['age']) {
maxAge = v['age'];
}
});
return {age: maxAge};
}
It's pretty simple:
collection.find({type : 'animal'}).sort({animal: -1}).limit(1);

Categories