How to join two JSON Array objects in Node - javascript

How to join two JSON Array objects in Node.
I want to join obj1 + obj2 so I can get the new JSON object:
obj1 = [ { t: 1, d: 'AAA', v: 'yes' },
{ t: 2, d: 'BBB', v: 'yes' }]
obj2 = [ { t: 3, d: 'CCC', v: 'yes' },
{ t: 4, d: 'DDD', v: 'yes' }]
output = [ { t: 1, d: 'AAA', v: 'yes' },
{ t: 2, d: 'BBB', v: 'yes' },
{ t: 3, d: 'CCC', v: 'yes' },
{ t: 4, d: 'DDD', v: 'yes' }]

var output = obj1.concat(obj2);

obj1 = [ { t: 1, d: 'AAA', v: 'yes' },
{ t: 2, d: 'BBB', v: 'yes' }]
obj2 = [ { t: 3, d: 'CCC', v: 'yes' },
{ t: 4, d: 'DDD', v: 'yes' }]
var output = obj1.concat(obj2);
console.log(output);

try
Object.assign(obj1, obj2);
For Details check Here
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

It can be done easily using ES6,
const output = [...obj1, ...obj2];

i already got an answer from the link provided by Pravin
var merge = function() {
var destination = {},
sources = [].slice.call( arguments, 0 );
sources.forEach(function( source ) {
var prop;
for ( prop in source ) {
if ( prop in destination && Array.isArray( destination[ prop ] ) ) {
// Concat Arrays
destination[ prop ] = destination[ prop ].concat( source[ prop ] );
} else if ( prop in destination && typeof destination[ prop ] === "object" ) {
// Merge Objects
destination[ prop ] = merge( destination[ prop ], source[ prop ] );
} else {
// Set new values
destination[ prop ] = source[ prop ];
}
}
});
return destination;
};
console.log(JSON.stringify(merge({ a: { b: 1, c: 2 } }, { a: { b: 3, d: 4 } })));

you can use jmerge package.
npm i jmerge
const jm = require('jmerge')
jm(obj1,obj2,obj3,...) //merging json data

I simply convert the arrays to strings, join them crudely with a comma, and then parse the result to JSON:
newJson=JSON.parse(
JSON.stringify(copyJsonObj).substring(0,JSON.stringify(copyJsonObj).length-1) +
',' +
JSON.stringify(jsonObj).substring(1)
)

Related

duplicate object inside array of objects conditionally in Javascript

I want to duplicate specific objects inside an array.
I have the array1 and I want to get the array2.
Example:
const array1 = [
{ a: String, b: Number, c: [3]},
{ a: String, b: Number, c: [12, 13]},
{ a: String, b: Number, c: [ 4, 5, 6]}
]
array2 = [
{ a: String, b: Number, c: [3]},
{ a: String, b: Number, c: [12]},
{ a: String, b: Number, c: [13]},
{ a: String, b: Number, c: [4]},
{ a: String, b: Number, c: [5]},
{ a: String, b: Number, c: [6]},
]
Array#reduce may come handy
const array1 = [
{ a: 'String', b: 'Number', c: [3]},
{ a: 'String', b: 'Number', c: [12, 13]},
{ a: 'String', b: 'Number', c: [ 4, 5, 6]}
];
const r = array1.reduce((s, a) =>
(s.push(a.c.length > 1 ? a.c.map((t) => ({ ...a, c: [t] })) : a), s), []);
document.write('<pre>' + JSON.stringify(r, null, 2) + '</pre>');
const array1 = [
{ a: String, b: Number, c: [3] },
{ a: String, b: Number, c: [12, 13] },
{ a: String, b: Number, c: [4, 5, 6] }
];
var array2 = [];
array1.map(obj => {
var obj2 = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (!Array.isArray(obj[key])) {
obj2[key] = obj[key];
} else {
obj[key].map(item => {
obj2[key] = item;
array2.push({ ...obj2 });
});
} // end if-else
} // end hasOwnProperty
} // end for
});
console.log(array2);

Compare two nested array and objects for find difference

I have two JSON data with multi-stage nesting. I want compare it by following conditions:
1) if name in the first object equal to name in the second object compare them prop arrays, else if nothing equal names in two object return empty array;
2) compare objects into two prop arrays and find difference;
3) return new object with difference from first and second arrays.
const p1 = [{
name: 'B [1]', // name equals and prop differnce, then comparing it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
C: { C: 78, D: 4, T: 7, } }],
}, {
name: 'B [2]', // name equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
D: { C: 3, D: 4, Y: 13 } }],
}, {
name: 'B [3]', // name equals and prop differnce, then comparing it
prop: [{
E: { A: 1, B: 2 },
R: { A: 1, B: 2 },
T: { C: 3, D: 4, } }],
}, {
name: 'B [4]', // name and prop equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
S: { A: 1, B: 2 },
D: { C: 3, D: 4, } }],
}]
const p2 = [{
name: 'B [1]', // name equals and prop differnce, then comparing it
prop: [{
A: { A: 1, B: 8 },
B: { A: 1, B: 2 },
C: { C: 3, T: 7, O: 9 } }],
}, {
name: 'B [6]', // name not equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
D: { C: 3, D: 4 } }],
}, {
name: 'B [3]', // name equals and prop differnce, then comparing it
prop: [{
E: { A: 1, B: 2 },
R: { A: 1, B: 2, U: 150 },
T: { C: 3, D: 4, } }],
}, {
name: 'B [4]', // name and prop equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
S: { A: 1, B: 2 },
D: { C: 3, D: 4, } }],
}]
The result should look like this:
const result = [{
name: 'B [1]',
propOne: [{
A: { B: 2 },
C: { C: 78, D: 4, O: 'Missing' }
}],
propTwo: [{
A: { B: 8 },
C: { C: 3, D: 'Missing', O: 9 }
}],
},{
name: 'B [3]',
propOne: [{
R: { U: 'Missing' }
}],
propTwo: [{
R: { U: 150 }
}]
}]
I also bitterly attach my worthless code here, which does nothing.
const compare = (p1, p2) => {
return p1.reduce((acc, curr) => {
p2.reduce((acc2, curr2) => {
if (curr.name === curr2.name) {
const keys1 = R.fromPairs(Object.keys(curr.prop[0]).map(x => ([x, curr.prop[0][x]])));
const keys2 = R.fromPairs(Object.keys(curr2.prop[0]).map(x => ([x, curr2.prop[0][x]])));
}
return acc;
}, [])
return acc;
}, [])
}
I would be extremely grateful for any help and advice.
All the difficulty resides in specing the expected behaviour of the comparison function:
for two objects (that I refer as values) a and b: {A:1,B:2} and {A:1,B:3,C:4}
the output of cmp(a,b) shall be:
foreach key of a:
if a[key] != b[key] (or b does not have k prop)
diff[key] = a[key]
else (value is equal, no diff)
foreach key of b not in a
diff[key] = Missing
hence (e.g) {B:2, C:'Missing'}
when comparing the values, if diff is empty, you can skip the current prop and when comparing props if the diff is empty skip the record (as if names were different)
function cmp(x,y){
let a = x.prop[0];
let b = y.prop[0];
return Object.keys(a).reduce((o,k)=>{
//compare the right value (such as { A: 1, B: 2 }). assumes primitive types
let u = a[k];
let v = b[k];
let diff = Object.keys(u).reduce((o,k)=>{
return u[k]==v[k]?o:(o[k] = u[k],o)
},{})
Object.keys(v).reduce((o,k)=>{
return u.hasOwnProperty(k)?o:(o[k]='Missing',o);
}, diff);
if(Object.keys(diff).length){
o[k] = diff;
}
return o;
},{});
}
function diff(p1,p2){
return p1.flatMap((o,i)=>{
if(p2[i].name != p1[i].name){
return []
}
let a = p1[i];
let b = p2[i];
let res = cmp(a,b);
if(!Object.keys(res).length){
return [];
}
return {name: a.name, propOne:res, propTwo:cmp(b,a)}
})
};
const p1 = [{
name: 'B [1]', // name equals and prop differnce, then comparing it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
C: { C: 78, D: 4, T: 7, } }],
}, {
name: 'B [2]', // name equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
D: { C: 3, D: 4, Y: 13 } }],
}, {
name: 'B [3]', // name equals and prop differnce, then comparing it
prop: [{
E: { A: 1, B: 2 },
R: { A: 1, B: 2 },
T: { C: 3, D: 4, } }],
}, {
name: 'B [4]', // name and prop equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
S: { A: 1, B: 2 },
D: { C: 3, D: 4, } }],
}]
const p2 = [{
name: 'B [1]', // name equals and prop differnce, then comparing it
prop: [{
A: { A: 1, B: 8 },
B: { A: 1, B: 2 },
C: { C: 3, T: 7, O: 9 } }],
}, {
name: 'B [6]', // name not equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
D: { C: 3, D: 4 } }],
}, {
name: 'B [3]', // name equals and prop differnce, then comparing it
prop: [{
E: { A: 1, B: 2 },
R: { A: 1, B: 2, U: 150 },
T: { C: 3, D: 4, } }],
}, {
name: 'B [4]', // name and prop equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
S: { A: 1, B: 2 },
D: { C: 3, D: 4, } }],
}];
console.log('result', JSON.stringify(diff(p1,p2),null,2))
It's kinda late, and i don't have time anymore for extensive tests right now, so this may have some bugs for unexpected cases (i hope not though). It's way too long for a comment, and discarding it would be a bit of a waste.
The below code contains two ways: one constructive, starting with empty objects, building up, and one the other way around, starting with the full objects, and then deleting.
Note, that in your data structures, there are several "one element arrays". If these can contain more than one element (they don't really make much sense to me, it's already objects within arrays within arrays, giving plenty of room for additional props), there needs to be one or two extra map steps, no big issue though.
const p1 = [{
name: 'B [1]', // name equals and prop differnce, then comparing it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
C: { C: 78, D: 4, T: 7, }
}],
}, {
name: 'B [2]', // name equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
D: { C: 3, D: 4, Y: 13 }
}],
}, {
name: 'B [3]', // name equals and prop differnce, then comparing it
prop: [{
E: { A: 1, B: 2 },
R: { A: 1, B: 2 },
T: { C: 3, D: 4, }
}],
}, {
name: 'B [4]', // name and prop equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
S: { A: 1, B: 2 },
D: { C: 3, D: 4, }
}],
}];
const p2 = [{
name: 'B [1]', // name equals and prop differnce, then comparing it
prop: [{
A: { A: 1, B: 8 },
B: { A: 1, B: 2 },
C: { C: 3, T: 7, O: 9 }
}],
}, {
name: 'B [6]', // name not equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
B: { A: 1, B: 2 },
D: { C: 3, D: 4 }
}],
}, {
name: 'B [3]', // name equals and prop differnce, then comparing it
prop: [{
E: { A: 1, B: 2 },
R: { A: 1, B: 2, U: 150 },
T: { C: 3, D: 4, }
}],
}, {
name: 'B [4]', // name and prop equals, then skiping it
prop: [{
A: { A: 1, B: 2 },
S: { A: 1, B: 2 },
D: { C: 3, D: 4, }
}],
}];
const result = [{
name: 'B [1]',
propOne: [{
A: { B: 2 },
C: { C: 78, D: 4, O: 'Missing' }
}],
propTwo: [{
A: { B: 8 },
C: { C: 3, D: 'Missing', O: 9 }
}],
},{
name: 'B [3]',
propOne: [{
R: { U: 'Missing' }
}],
propTwo: [{
R: { U: 150 }
}]
}]
const diffDestructive = (a, b) => {
/**
* Copy the objects, remove all identical properties recursively,
* then add "Missing" properties for all properties from either side
* that doesn't exist on the other.
*/
const remove = (x, y) => {
for (let key of Object.keys(x)) {
// hasOwnProperty is only for the degenerate case { prop: undefined }
if (x[key] === y[key] && y.hasOwnProperty(key)) {
delete x[key];
delete y[key];
} // typeof null === "object", therefore an additional check is needed
else if (x[key] && typeof x[key] === "object" && y[key] && typeof y[key] === "object") {
remove(x[key], y[key]);
if ([x, y].every(e => Object.keys(e[key]).length === 0)) {
delete x[key];
delete y[key];
}
}
}
};
const addMissingNotes = (x, y) => {
for (let key of Object.keys(x)) {
if (!(y.hasOwnProperty(key))) y[key] = "Missing";
else if (x[key] && typeof x[key] === "object" && y[key] && typeof y[key] === "object")
addMissingNotes(x[key], y[key]);
}
};
// quick and dirty object deep-copy
let [modA, modB] = [a, b].map(e => JSON.parse(JSON.stringify(e)));
remove(modA, modB);
addMissingNotes(modA, modB);
addMissingNotes(modB, modA);
return [modA, modB];
};
const diffConstructive = (a, b) => {
/**
* Add differing properties to the result step by step.
* Nested objects are handled recursively.
*/
let diffA = {}, diffB = {};
for (let key of Object.keys(a)) {
//properties that a and b share
if (b.hasOwnProperty(key)) {
if (a[key] && typeof a[key] === "object" && b[key] && typeof b[key] === "object") {
let subDiffs = diffConstructive(a[key], b[key]);
// The way the construction works, Object.keys(subDiffs[0]).length !== 0 would be enough.
if (subDiffs.some(e => Object.keys(e).length !== 0)) {
[diffA[key], diffB[key]] = subDiffs;
}
} else if (a[key] !== b[key]) {
diffA[key] = a[key];
diffB[key] = b[key];
}
} // properties that a has but b doesn't
else {
diffA[key] = a[key];
diffB[key] = "Missing";
}
}
// properties that b has but a doesn't
for (let key of Object.keys(b)) {
if (!a.hasOwnProperty(key)) {
diffB[key] = b[key];
diffA[key] = "Missing";
}
}
return [diffA, diffB];
};
const compare = (a, b, method) => a
.map((e, i) => [e, b[i]])
//same name only
.filter(([a, b]) => a.name === b.name)
// formatting
.map(([a, b]) => {
const [diffA, diffB] = method(a.prop[0], b.prop[0]);
return {
name: a.name,
propOne: [diffA],
propTwo: [diffB]
};
})
// There must be a difference
.filter(e => [e.propOne[0], e.propTwo[0]].some(e => Object.keys(e).length !== 0));
const destructive = compare(p1, p2, diffDestructive);
const constructive = compare(p1, p2, diffConstructive);
console.log(`Constructive method gives the wanted result: ${_.isEqual(result, destructive)}`);
console.log(`Destructive method gives the wanted result: ${_.isEqual(result, constructive)}`);
<!--
this is only for a deepequals function, _.isEqual,
and only used for checking the results. I could have copied
one into the code, but why make this even longer...
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.core.min.js"></script>

Add object and array for same properties

var obj = {x:{y: {a: 1, b:2}}, p: 11}
var arr = [{x: {y: {c: 3}}},{x: {y: {d: 4}}}]
it can be done by lodash merge(obj, ...arr)
but I don't want to use lodash merge method
outputObj = {x:{y: {a: 1, b:2, c: 3, d: 4}}, p: 11}
You could take an iterative and recursive approach and check the type of the value and take either an array or object if a parent property is not given.
function merge(target, ...source) {
source.forEach(s => Object.entries(s).forEach(([k, v]) => {
if (v && typeof v === 'object') {
merge(target[k] = target[k] || (Array.isArray(v) ? [] : {}), v);
} else {
target[k] = v;
}
}));
}
var obj = { x: { y: { a: 1, b: 2 } }, p: 11 },
arr = [{ x: { y: { c: 3 } } }, { x: { y: { d: 4 } } }]
merge(obj, ...arr)
console.log(obj);
I found you can do this in "one line" using recursive reduction
const
merge = (target, obj) =>
Object.keys (obj).reduce((merged, key) => ({
...merged,
[key]:[obj[key]].reduce(merge, target[key])||obj[key]
}), target),
merged = arr.reduce (merge,obj);
console.log (merged);
<script>
var obj = {x:{y: {a: 1, b:2}}, p: 11}
var arr = [{x: {y: {c: 3}}},{x: {y: {d: 4}}}]
</script>

Using Object.assign on an object within an object

How do I use Object.assign to update the second object in the allMsgs array?
I have:
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: [],
}
]
}
I want to have a copy of v so that it is:
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: ['newItem],
}
]
}
How do I use Object.assign for this?
Simply select the part which you want to update
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: [],
}
]
};
let vCopy = { allMsgs: v.allMsgs.map(msg => Object.assign({}, msg))};
vCopy.allMsgs[1] = Object.assign(vCopy.allMsgs[1], { b: ['newItem'] });
console.log('copy', vCopy);
console.log('actual', v);
Without Object.assign, you could address the array directly and push the value.
var v = { allMsgs: [{ a: 111, b: [] }, { a: 222, b: [] }] };
v.allMsgs[1].b.push('newItem');
console.log(v);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If the goal is not to mutate the original object, then you would do it like this:
let v = {
allMsgs: [
{ a: 111, b: [] },
{ a: 222, b: [] }
]
};
let w = { allMsgs: Object.assign([...v.allMsgs],
{ 1: Object.assign({}, v.allMsgs[1],
{b: ['newItem']}
)}
)};
console.log('updated =', w);
console.log('original =', v);
Note that here the first object in allMsgs is still shared between the two objects. Only the one you wanted to change is (obviously) separate.
Libraries like immutable.js have nice methods for making such updates using a concise syntax.

How to convert an array of dictionaries to an array of arrays?

How can I easily convert this (array of dictionaries):
[ { a: 1,
b: 1,
c: 'something',
d: 1 },
{ a: 23443,
b: 2111,
c: 'something 2',
d: 1456 }
]
to this (array of arrays):
[ [ 1,
1,
'something',
1 ],
[ 23443,
2111,
'something2',
1456 ]
]
Use Array.prototype.map and for-in loop
The map() method creates a new array with the results of calling a provided function on every element in this array
The for...in statement iterates over the enumerable properties of an object
Try this:
var input = [{
a: 1,
b: 1,
c: 'something',
d: 1
}, {
a: 23443,
b: 2111,
c: 'something2',
d: 1456
}];
var op = input.map(function(inp) {
var arr = [];
for (var i in inp) {
arr.push(inp[i]);
}
return arr;
});
console.log(op);
OR use Object.keys(YOUR_OBJECT):
var input = [{
a: 1,
b: 1,
c: 'something',
d: 1
}, {
a: 23443,
b: 2111,
c: 'something2',
d: 1456
}];
var op = input.map(function(inp) {
return Object.keys(inp).map(function(key) {
return inp[key];
})
});
console.log(op);

Categories