compare two Object array and match value - javascript

I have two Object of array like following
var a={
firstObj:
[
{
Ref: "5ca3cd6aefbc9f1782b5db53",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
}
]
};
var b={
secondObj: [
{
_id: "5ca3cd6aefbc9f1782b5db53"
},
{
_id: "5ca3cdc6efbc9f1782b5db5c"
},
]
}
I want to check if a.firstObj has matching Ref to b.secondObj._id if it has then I am trying to assign into firstObj element to matching b.secondObj.new but somehow _id is not matching
I am trying through map
a.firstObj.map(item =>
b.secondObj.map((_item, index) => {
console.log(_item._id.toString());
console.log(item.Ref.toString());
if (_item._id == item.Ref) {
b.secondObj[index].new = item;
}
})
);

AFAI tested... yes it's matching. Take a look:
var a={
firstObj:
[
{
Ref: "5ca3cd6aefbc9f1782b5db53",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
}
]
};
var b={
secondObj: [
{
_id: "5ca3cd6aefbc9f1782b5db53"
},
{
_id: "5ca3cdc6efbc9f1782b5db5c"
},
]
}
a.firstObj.map(item =>
b.secondObj.map((_item, index) => {
//console.log(_item._id.toString());
//console.log(item.Ref.toString());
if (_item._id == item.Ref) {
b.secondObj[index].new = item;
}
})
);
console.log(b)
You probably missed something. If there's anything else you want to know, please reformulate and I'll change the answer.
Please understand that with this code, as a object has many equal Ref elements, the association will be with the last Ref.

You can do a map with an inner reduce:
var a={
firstObj:
[
{
Ref: "5ca3cd6aefbc9f1782b5db53",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hhhh"
}
]
};
var b={
secondObj: [
{
_id: "5ca3cd6aefbc9f1782b5db53"
},
{
_id: "5ca3cdc6efbc9f1782b5db5c"
},
]
}
function mergeByEqProp (propA, propB, listA, listB) {
return listB.map(function (b) {
return listA.reduce(function (acc, a) {
if (!acc && a[propA] === b[propB]) {
return Object.assign({}, b, {new: a});
}
return acc;
}, null);
});
}
console.log(mergeByEqProp('Ref', '_id', a.firstObj, b.secondObj));
It first maps over the second list and then reduces the items in the first list until it finds a match. As soon as it finds a match, it always returns that. I added that functionality because it looks like there is some repetition in a.firstObj (have a close look at the Ref properties). In case that's fine, just change the if (!acc && a[propA] === b[propB]) { part to if (a[propA] === b[propB]) {.
The Object.assign part deserves a bit of explanation as well:
First of all, in case you don't work in an ES6/ES2015+ environment, you need another function as a replacement – $.extend for example works well. Or write your own, like:
function assign (a /*, ...rest */) {
var r = Array.prototype.slice.call(arguments, 1);
return r.reduce(function (acc, x) {
for (var y in x) {
if (x.hasOwnProperty(y)) { acc[y] = x[y]; }
}
return acc;
}, a);
}
The other thing to explain is the empty {}: It is merely there to create a copy first and alter that copy instead of the original item. If that doesn't bother you, just use Object.assign(b, a) (or your own assign(b, a) respectively).

/* This code will identify all the items that match with Ref id and then assign them into new property inside the secondObj as an array */
<script type="text/javascript">
var a={
firstObj:
[
{
Ref: "5ca3cd6aefbc9f1782b5db53",
status: "abcd"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "efgh"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "hijk"
},
{
Ref: "5ca3cdc6efbc9f1782b5db5c",
status: "lmno"
}
]
};
var b={
secondObj: [
{
_id: "5ca3cd6aefbc9f1782b5db53"
},
{
_id: "5ca3cdc6efbc9f1782b5db5c"
},
]
}
let equality = [];
for(let i=0; i<b.secondObj.length ; i++){
let itemB = b.secondObj[i];
equality.push(a.firstObj.filter(itemA => itemA.Ref == itemB._id)) ;
}
equality.map((value, index) => b.secondObj[index].new = value); //<=== in case if there are more than one equal items in firstObj
//equality.map((value, index) => b.secondObj[index].new = value[0]); <== only asign one item to 'new'
console.log(b);
</script>

Related

Within an array of objects modify all previous objects to an object with a specific property

I have an array of objects, and according to a property inserted in one of them i would like to mark or select all the objects previous to that object container of the specific property
My array is in this way:
const arrX= [
{ status: '1' },
{ status: '2'},
{ status: '3', imHere: true },
{ status: '4' },
];
Then due to the property imHere on arrX[2], the positions arrX[0] and arrX[1] should be modified.
My expected result would be :
const arrX= [
{ status: '1',wasHere:true },
{ status: '2',wasHere:true},
{ status: '3', imHere: true },
{ status: '4' },
];
I know that the map method would be quite useful in this case, but can´t find the way to check from index of object containing imHere backwards the former positions
One approach is to use .findIndex() and .map():
const arrX= [{ status: '1' }, { status: '2'}, { status: '3', imHere: true }, { status: '4'}];
const imHereIndex = arrX.findIndex(({imHere}) => imHere === true);
const result = arrX.map((val, index) => index < imHereIndex
? { ...val, wasHere: true }
: val
);
console.log(result);
Even if #Kinglish answer works like a charm I want to share another way to achieve your goal. This road is surely longer than Kinglish ones, never then less is a good alternative.
{ status: '4' },
];
function findProperty(arr) {
const hasProperty = arr.findIndex(el => Object.keys(el).includes('imHere'))
const addNewProperty = arr.map((el,i) => (i < hasProperty) ? {...el, wasHere: true} : el)
return addNewProperty
}
const updatedArray = findProperty(arrX)
console.log(updatedArray)
Here's one method for it using Array#reduce and a boolean to track whether we've encountered inHere
const arrX = [
{status: '1'},
{status: '2'},
{status: '3',imHere: true},
{status: '4'},
];
let found = false,
updated = arrX.reduce((b, a) => {
found = found || (a.hasOwnProperty('imHere') && a.imHere === true)
if (!found) a.wasHere = true;
return b.concat(a);
}, [])
console.log(updated)
A simple loop - breaking out of it when one of the objects contains imHere, otherwise adding in a wasHere property.
function update(arr) {
for (let i = 0; i < arr.length; i++) {
if (!arr[i].imHere) {
arr[i].wasHere = true;
} else {
break;
}
}
return arr;
}
const arr = [
{ status: '1' },
{ status: '2' },
{ status: '3', imHere: true },
{ status: '4' },
];
console.log(update(arr));

Destructuring an object in order to make the all properties none nested / single level

I have this object with the following nested properties.
{
_id: {
agent_info: {
name: 'Ritu',
status: 'active',
avatar: null
}
},
avg_score: 100,
}
I am trying to deconstruct it so that it looks like this.
{
name: 'Ritu',
status: 'active',
avatar: null,
avg_score: 100,
}
I tried using this const { _id:{...agent_info} } = user; but the output remains the same and the object is not altered.
Destructuring won't alter the object. It might create a new object, but it won't modify the original.
You can't use a single destructuring operation to get the result you want. You can get close, but it takes two steps.
const { _id: { agent_info: { ...result } } } = original;
result.avg_score = original.avg_score;
Live Example:
const original = {
_id: {
agent_info: {
name: 'Ritu',
status: 'active',
avatar: null
}
},
avg_score: 100,
};
const { _id: { agent_info: { ...result } } } = original;
result.avg_score = original.avg_score;
console.log(result);
That copies everything from original._id.agent_info into a new object referenced by the result constant, then adds in avg_score.
You could also do it without reusing original, by grabbing avg_score in the same operation that creates result:
const { _id: { agent_info: { ...result } }, avg_score } = original;
result.avg_score = avg_score;
Live Example:
const original = {
_id: {
agent_info: {
name: 'Ritu',
status: 'active',
avatar: null
}
},
avg_score: 100,
};
const { _id: { agent_info: { ...result } }, avg_score } = original;
result.avg_score = avg_score;
console.log(result);
...but that leaves an avg_score constant lying around (which is harmless, but...).
You can achieve this object destructuring using something that is called deep property.
const obj = {
_id: {
agent_info: {
name: 'Ritu',
status: 'active',
avatar: null
}
},
avg_score: 100,
};
const {_id:{ agent_info:{ ...res }}} = obj;
res["avg_Score"] = obj.avg_score;
console.log(res);
Check out the this link for more info

Finding a value in nested array then returning a value from the upper scope

What I am trying to achieve is:
Find if the text object within array is empty.
If criteria from no1 is matched, then return id value that sits in the top level of that object.
https://codesandbox.io/s/cranky-swirles-gb6ct?file=/src/App.js:410-412
In the code sandbox's example I have added two objects, with empty text strings and in that case I would expect to get an array of strings back (result = ['662e4120', '782h7a9x'])
I am able to find empty values, however I am not sure how to return object from the upper scope.
If you can't access the codeSandbox, snippet is attached just below:
const array = [
{
id: "5548d3c2",
state: {
properties: [
{
text: "text",
key: "fs5a"
}
]
}
},
{
id: "662e4120",
state: {
properties: [
{
text: "",
key: "m03n"
}
]
}
},
{
id: "782h7a9x",
state: {
properties: [
{
text: "",
key: "y5x1"
}
]
}
}];
const findItem = () => {
return array
.map((item) => item.state)
.map((item) => item.properties)
.flat()
.filter((item) => item.text === "");
};
Try to do something like this https://codesandbox.io/s/jovial-mcnulty-2fwh4
export default function App() {
const array = [
{
id: "5548d3c2",
state: {
properties: [
{
text: "text",
key: "fs5a"
}
]
}
},
{
id: "662e4120",
state: {
properties: [
{
text: "",
key: "m03n"
}
]
}
},
{
id: "782h7a9x",
state: {
properties: [
{
text: "",
key: "y5x1"
}
]
}
}
];
const findItem = () => {
return array.filter(obj=>obj.state.properties[0].text==="").map(obj=>obj.id)
};
console.log(findItem());
return <div className="App"></div>;
}
Here, we are filtering on the original array based on a predicate which is obj=>obj.state.properties[0].text==="". This basically get all the elements of the array which satisfy this predicate function. After this we are just applying map over the result to get the ids of the array elements satisfying this predicate function.
To get an array with the ids of the objects with no text you have to change the order or your iterations.
.filter() the array for the elements with empty text fields.
.map() the remaining elements to the values you are aiming for
When mapping or filtering you can't just go one but as many levels deep as you like. Since 'properties' holds an array and you want the first element, you can access that with the index array[0] (with that the flat() you did is superfluous)
const findItem = () => {
return array
.filter(item => item.state.properties[0].text === "") // (2) [{…}, {…}] the original items with no text
.map(item => item.id) // ['662e4120', '782h7a9x']
};
(code might be as well embedded as a snippet, which can be run directly)
const array = [
{
id: "5548d3c2",
state: {
properties: [
{
text: "text",
key: "fs5a"
}
]
}
},
{
id: "662e4120",
state: {
properties: [
{
text: "",
key: "m03n"
}
]
}
},
{
id: "782h7a9x",
state: {
properties: [
{
text: "",
key: "y5x1"
}
]
}
}];
const findItem = () => {
return array
.filter(item => item.state.properties[0].text === "") // (2) [{…}, {…}] the original items with no text
.map(item => item.id) // ['662e4120', '782h7a9x']
};
console.log(findItem())

Removing repeating elements in a array based on specific data [Discord.js]

I have a problem here that I can't deal with. There is little written about this on the internet. Well, when starting out, I need to make a function that will remove the duplicate data from the table, but the comparison of this data must be based on the data from the table object, below I will give an example because I do not know if I explained it well.
[
{
id: 1234,
user: {
nickname: 'a' <-
}
},
{
id: 1234,
user: {
nickname: 'b' <-
}
},
{
id: 1234,
user: {
nickname: 'a' <-
}
},
]
Data is to be compared according to user.nickname.
I tried to do it this way
array.filter((value, index) => array.indexOf (value.user.nickname) === index)
but all I got was a blank array
[]
If anyone can help, I will be grateful because I have this situation.
Your approach is wrong. Here's one way you can do it instead:
const mapOfNicknames = {};
array.forEach((e)=> {
const nick = e.user.nickname;
// check if nick already exists in map
if ( !mapOfNicknames[nick] ) {
mapOfNicknames[nick] = e;
}
});
// at this point, mapOfNicknames has a unique list
const uniqueArray = Object.keys(mapOfNicknames).map( k => mapOfNicknames[k] );
Using Array.filter as you try, should be a proper aproat:
const users = [
{
id: 1234,
user: {
nickname: "a",
},
},
{
id: 1234,
user: {
nickname: "b",
},
},
{
id: 1234,
user: {
nickname: "a",
},
},
];
let filteruniquebyUserName = users.filter(
(user, index, users) => users.findIndex((compareUser) => compareUser.user.nickname === user.user.nickname) === index
);
console.log(filteruniquebyUserName);
See: How to remove all duplicates from an array of objects?
Another way a little more extended but easier to understand:
const data = [
{
id: 1234,
user: {
nickname: "a",
},
},
{
id: 1234,
user: {
nickname: "b",
},
},
{
id: 1234,
user: {
nickname: "b",
},
},
{
id: 1234,
user: {
nickname: "a",
},
},
];
let elementRepeated = [];
let filteruniquebyUserName = data.filter((user, index, data) => {
if(elementRepeated.includes(user.user.nickname)) return;
const numberOfRepeatUser = data.filter(element => element.user.nickname === user.user.nickname).length;
if(numberOfRepeatUser > 1) elementRepeated.push(user.user.nickname);
return user
});
console.log(filteruniquebyUserName);
Apparently you can't do an indexOf check in a nested object like you are doing it right now. See: Javascript indexOf on an array of objects

Flatten a nested json and get object keys

I get json from client side which is nested, I want to faltten it and make the children object keys, preferably using underscore.js.
For example that is my json:
var data = {
or:[
{
dealershipCompany : 11
},
{
authType: 'google'
}],
and: [
{
or: [
{
firstName: {'contains': 'search'}
},
{
lastName: {'contains': 'search'}
},
{
email: {'contains': 'search'}
}]
}]
};
I want to remove both 'or' & 'and'
and when I get the object keys using Object.keys(data) I get
['0','1','2','3','4','5']
but I want it to be like this
['dealershipCompany', 'authType', 'firstName', 'lastName','email']
I tried several times to flatten it by myself but always object keys get numbered
Here the link of jsFiddle
This should work:
var data = {
or:[
{ dealershipCompany : 11 },
{ authType: 'google' }
],
and: [ {
or: [
{ firstName: {'contains': 'search'} },
{ lastName: {'contains': 'search'} },
{ email: {'contains': 'search'} }
]
}]
};
function getOnlyObjects(data) {
var result = [];
if (Array.isArray(data)) {
data.forEach(function(item) {
result = result.concat(
getOnlyObjects(item)
);
});
}
else {
Object.keys(data).forEach(function(key) {
if (Array.isArray(data[key])) {
result = result.concat(
getOnlyObjects(data[key])
);
}
else {
result = result.concat(data);
}
});
}
return result;
}
function getData(data) {
return getOnlyObjects(data).map(function(item) {
return Object.keys(item)[0];
});
}
console.log(getData(data));
Outputs:
["dealershipCompany", "authType", "firstName", "lastName", "email"]
When you use Object.keys over array, you will get indexes, hence you were getting ['0','1','2','3','4','5'].
Edit 1
Have migrated === 'and', === 'or' to an array exceptionList. You can add further keys that you need to filter. This will keep filtering manageable and condition clean.
Code
JSFiddle
var data = {
or: [{
dealershipCompany: 11
}, {
authType: 'google'
}],
and: [{
or: [{
firstName: {
'contains': 'search'
}
}, {
lastName: {
'contains': 'search'
}
}, {
email: {
'contains': 'search'
}
}, ]
}]
};
var result = [];
// You can add further keys that you want to filter
var exceptionList = ["and", "or"];
function getKeys(obj) {
var _keys = Object.keys(obj);
_keys.forEach(function(key) {
// Check if key is either,`and`, `or`, or an index of array.
if (exceptionList.indexOf(key) >=0 || !isNaN(key)) {
getKeys(obj[key]);
} else {
result.push(key);
}
});
}
getKeys(data);
console.log(result)

Categories