Conditionally combine arrays of objects based on Ids - javascript

How can I add the status property from object2 into object1 based on newEmployeeId matching employeeId only if the dependentId is NULL.
For example: An array where Ben, Jim and Dan have statuses of Complete, Updating and Finished, respectively. Lauren should not have a status.
var object1 = [
{ name: 'Ben', employeeId: 1, dependentId: null },
{ name: 'Lauren', employeeId: 1, dependentId: 5},
{ name: 'Jim', employeeId: 2, dependentId: null },
{ name: 'Dan', employeeId: 3, dependentId: null}
];
var object2 = [
{ status: 'Complete', newEmployeeId: 1 },
{ status: 'Updating', newEmployeeId: 2 },
{ status: 'Finished', newEmployeeId: 3 }
];

There are a number of ways to approach this. Here's one:
object1.forEach(o1 => {
if (o1.dependentId !== null) return;
const o2 = object2.find(o2 => o2.newEmployeeId === o1.employeeId);
if (!o2) return;
o1.status = o2.status;
})
The idea is that we loop over each entry of object1 via the forEach() array method. For each such entry o1, we first check to make sure that its dependentId is null (because you only want to operate on such entries) and give up if it isn't.
Then we search the object2 array for a matching entry o2 via the find() array method. If no such entry is found, o2 will be undefined and we we give up. Otherwise we set o1's status property to match that of o2.
For the example code you gave, this produces the following final state for object1:
console.log(object1);
/* [{
"name": "Ben",
"employeeId": 1,
"dependentId": null,
"status": "Complete"
}, {
"name": "Lauren",
"employeeId": 1,
"dependentId": 5
}, {
"name": "Jim",
"employeeId": 2,
"dependentId": null,
"status": "Updating"
}, {
"name": "Dan",
"employeeId": 3,
"dependentId": null,
"status": "Finished"
}] */
Note that, depending on your use cases, you might want to change the implementation. For example, if your arrays have many entries, you might want to index object2 by newEmployeeId ahead of time instead of finding its elements over and over again. But that's outside the scope of the question as asked.
Playground link to code

Try this:
object1.forEach(item => {
if (!item.dependentId) {
result = object2.find(item2 => item2.newEmployeeId === item.employeeId)
item.status = result.status
}
})

Related

Functional Programming exercise I can't figure out

I've been looking at a problem for hours and failing to find a solution. I'm given an array of customer objects.
In each customer object is an array of friends.
In the array of friends is an object for each friend, containing some data, including a name key/value pair.
What I'm trying to solve for: I'm given this customers array and a customer's name. I need to create a function to find if this customer name is in any other customer's friend lists, and if so, return an array of those customer's names.
Below is a customer list. And as an example, one of the customers is Olga Newton. What the code should be doing is seeing that Olga Newton is a customer and is also in the friends lists of Regina and Jay, and should be returning an array of Regina and Jay.
I thought I could do this simply with a filter function, but because the friends list is an array with more objects, this is adding level of complexity for me I can't figure out.
Below is a customer array. The out put should be
['Regina', 'Jay']
and what I've gotten has either been
[{fullCustomerObj1}, {fullCustomerObj2}]
or
[ ]
What am I missing?
Here is the customer array:
var customers = [{
name: "Olga Newton",
age: 43,
balance: "$3,400",
friends: [{
id: 0,
name: "Justice Lara"
}, {
id: 1,
name: "Duke Patrick"
}, {
id: 2,
name: "Herring Hull"
}, {
id: 3,
name: "Johnnie Berg"
}]
}, {
name: "Regina",
age: 53,
balance: "$4,000",
friends: [{
id: 0,
name: "Cheryl Kent"
}, {
id: 1,
name: "Cynthia Wells"
}, {
id: 2,
name: "Gutierrez Waters"
}, {
id: 3,
name: "Olga Newton"
}]
}, {
name: "Jay",
age: 28,
balance: "$3,000",
friends: [{
id: 0,
name: "Cross Barnett"
}, {
id: 1,
name: "Raquel Haney"
}, {
id: 2,
name: "Olga Newton"
}, {
id: 3,
name: "Shelly Walton"
}]
}];
Use filter and map, please.
function friends(c, name){
return c.filter((a) => {
return a.friends.map(b => b.name).includes(name)
}).map(a => a.name);
}
console.log(friends(customers, "Olga Newton"));
// ['Regina', 'Jay']
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
We look to an array (friends[]) inside anther (customers[]), So used two for loops, the first determine witch customer will look for his friends, and the second the array will search inside, then set if statement if the cust name is inside friends[]: adding the customer name to customerFriends[] array, At the end return the customerFriends[].
let cust = "Olga Newton"; // Get the customer name who you look for his friends.
const findFriend = (cust, arrs) => { // Create findFriend function.
let customerFriends = []; // Create an array to set the result to it.
for (let i = 0; i < arrs.length; i++) { // For each Customer.
for (const arr of arrs[i].friends) { // For each Friend.
if (arr.name === cust) { // Use Strict equality to find Customer name in friends[].
customerFriends.push(arrs[i].name); // Add the customer name to the customerFriends[].
}
}
}
return customerFriends;// Return the final results.
}
console.log(findFriend(cust, customers)); // Call the function.

How to filter few properties of an object which is in Array of objects if one property equals property from another object

I have a object which has some properties for one user, and I have array of objects which is returned from API.
My goal is to check which object of Array of objects has the same property as the one single initial object, and then it should return only part of it's properities.
I have tried to use .map on Array of objects but it seems not workig.
Below is the code example. I have also prepared codesandbox if You wish.
const user =
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
car: "audi"
}
;
const usersAnimal = [
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
animal: "cat",
animalSize: "small",
animalName: "Bat"
},
{
name: "john",
lastName: "smith",
fullName: "john smith",
animal: "dog",
animalSize: "middle",
animalName: "Jerry"
},
{
name: "Anna",
lastName: "Nilsson",
fullName: "Anna Nilsson",
animal: "cow",
animalSize: "big",
animalName: "Dorrie"
}
];
const filtered = usersAnimal.map((userAnimal)=>userAnimal.fullName === user.fullName && return userAnimal.animalName & userAnimal.animalSize & userAnimal.animal);
thanks
https://codesandbox.io/s/admiring-edison-qxff42?file=/src/App.js
For case like this, it would be far easier if you filter it out first then proceed using map:
const filtered = usersAnimal
.filter((animal) => animal.fullName === user.fullName)
.map(({ animalName, animalSize, animal }) => {
return {
animalName,
animalSize,
animal
};
});
I am providing a for loop solution as I haven't learnt many array methods in javascript.
For me the simplest option is to use a for loop and an if check to loop through the arrays values to check for included values.
for (let v in usersAnimal) {
if (usersAnimal[v].fullName === user.fullName) {
console.log(usersAnimal[v])
}
}
The code above will log the entire usersAnimal object containing the fullname we are looking for.
{
name: 'jan',
lastName: 'kowalski',
fullName: 'jan kowalski',
animal: 'cat',
animalSize: 'small',
animalName: 'Bat'
}
commented for further understanding
for (let v in usersAnimal) {
//loops though the array
if (usersAnimal[v].fullName === user.fullName) {
//when the index value 'v' has a fullname that matches the user fullname value
// it passes the if check and logs that object value
return console.log(usersAnimal[v])
//return true...
}
//return null
}
//etc
If you want to filter, I recommend you to use filter.
The map method will create a new array, the content of which is the set of results returned by each element of the original array after the callback function is operated
const user = {name:"jan",lastName:"kowalski",fullName:"jan kowalski",car:"audi"};
const usersAnimal = [{name:"jan",lastName:"kowalski",fullName:"jan kowalski",animal:"cat",animalSize:"small",animalName:"Bat"},{name:"john",lastName:"smith",fullName:"john smith",animal:"dog",animalSize:"middle",animalName:"Jerry"}];
// Get an array of matching objects
let filtered =
usersAnimal.filter(o => o.fullName === user.fullName);
// You get the filtered array, then you can get the required properties
filtered.forEach(o => {
console.log(
'animal:%s, animalSize:%s, animalName:%s',
o?.animal, o?.animalSize, o?.animalName
);
});
// Then use map to process each element
filtered = filtered.map(o => {
const {animal, animalSize, animalName} = o;
return {animal, animalSize, animalName};
});
console.log('filtered', filtered);

IndexOf over a nested array response graph returning just []

I am trying to filter some articles from a graphql response, by articleTag. Se my structure below:
{
"id": "41744081",
"articleTitle": "text",
"articleContent": "text",
"categoryName": { "categoryName": "Company", "id": "38775744" },
"articleTags": [
{ "articleTag": "event", "id": "37056861" },
{ "articleTag": "car", "id": "37052481" },
]
},
{
"id": "41754317",
"articleTitle": "text",
"articleContent": "text",
"categoryName": { "categoryName": "Sales and Martketing", "id": "38775763" },
"articleTags": [{ "articleTag": "technology", "id": "37056753" }]
},
...
But when applying my function:
notificationFiltered () {
var articleResponse = this.response.allArticles;
var routeParam = this.$route.params.tagName; //contains the id of the tag
const filteredTag = articleResponse.filter((item) => {
return (item.articleTags.indexOf(routeParam) >= 0);
});
console.log(filteredTag);
},
When I'm "console.log" the result I get only a "[]". Not sure if is related with the way of query is being render, in the API I get the same formation but with this slightly difference
{
"data": {
"allArticles": [... the specify structure above]
}
}
while printing that with vue {{response.allArticles}} I just get the first structure, I think it shouldn't matter?
Thanks in advance for the advice
You won't be able to use indexOf for array of objects to find a matching object - only strict equality is needed, and that's hard to get in the reference land. Consider this:
const objs = [
{ foo: 'bar' },
{ foo: 'baz' },
{ foo: 'foo' } // whatever
];
const needle = { foo: 'baz' };
objs.indexOf(needle);
// -1
What? Yes, there's an object looking exactly like needle in that array - but it's a different object:
objs[1] === needle; // false
That's why indexOf just goes past that one - and gives out -1, a "not found" result.
What you should be able to use in this case is findIndex. Still you need to build the predicate to have a match. For example:
const objs = [
{ foo: 'bar' },
{ foo: 'baz' },
{ foo: 'foo' }
];
const needle = { foo: 'baz' };
objs.findIndex(el => JSON.stringify(el) === JSON.stringify(needle));
// 1
In this example, comparing results of JSON.stringify in the predicate function is a poor man's _.isEqual - just to illustrate the concept. What you should consider actually using in your code is either _.isEqual itself, or similar function available in toolkit of your choice.
Alternatively, you can just check for specific fields' values:
objs.findIndex(el => el.foo === needle.foo); // still 1
This will apparently find objects even if their other properties do not match though.

Is there a better way to iterate through an object of unknown depth than using map statements nested to the maximum possible depth?

I have nested employee objects of different, unknown depths. Each object has a children property, which is an array of the employee objects who report to that employee. These child objects have the same attributes as the top level object and may or may not have employee objects in their own children property.
I need to go through each employee object's array of employee objects and add each of those objects to one of two different arrays, depending on whether the object has other employee objects in it's own "children" property. These arrays are also properties of the employee objects. Employees with empty "children" arrays will be added to their parent employee's nonManagersUnder array, while those with objects in their children array will be added to the managersUnder array.
The nested employee objects look like this:
{
id: "n1",
"isActive": true,
age: 38,
name: "Barb Smith",
"phone": "+1 (882) 547-3581",
"hired": "2016-08-08T12:46:19 +07:00",
children: [
{
id: "n10",
"isActive": true,
age: 37,
name: "Elsie MacDonald",
"phone": "+1 (958) 558-2389",
"hired": "2015-08-15T04:44:49 +07:00",
children: [
]
},
{
id: "n11",
"isActive": true,
age: 29,
name: "Peter Chen",
"phone": "+1 (881) 574-3927",
"hired": "2015-02-16T12:11:11 +08:00",
children: [
]
},
{
id: "n12",
"isActive": true,
age: 32,
name: "Ty Wilder",
"phone": "+1 (990) 506-2830",
"hired": "2019-09-17T06:29:16 +07:00",
children: [
]
}
}
This is a very simple example since I didn't want to put something several hundred lines long in my post, but the structure is the same. Just imagine that each of the secondary employee objects has its own children.
You'll notice that the nonManagersUnder and managersUnder arrays are not attributes of the employee objects to start with. That is because in my current solution they are dynamically assigned.
Here is that solution:
countManagers = (employee) => {
let midManagers = []
let nonManagers = []
employee.children.map(child =>{
if(child.children.length == 0) {
nonManagers.push(child);
}else {
midManagers.push(child);
child.children.map(grandChild => {
if(grandChild.children.length == 0){
nonManagers.push(grandChild);
}else {
midManagers.push(grandChild);
grandChild.children.map(greatGrand => {
if(greatGrand.children.length == 0){
nonManagers.push(greatGrand)
} else {
midManagers.push(greatGrand);
greatGrand.children.map(grand3 => {
if(grand3.children.length==0){
nonManagers.push(grand3);
} else {
midManagers.push(grand3);
grand3.children.map(grand4 => {
if(grand4.children.length==0){
nonManagers.push(grand4);
} else {
midManagers.push(grand4);
}
})
}
})
}
})
}
})
}
})
console.log(midManagers);
// console.log(nonManagers);
employee.managersUnder = (midManagers);
employee.nonManagersUnder=(nonManagers)
}
As you can see, it is simply nested map operators and some conditionals, nested to the maximum depth an employee object can be nested. This solution does work, but is very ugly and I'm almost certain there is a better way of doing this. A better solution would work for an object of any depth. This only works for objects where the depth is equal to or less than the number of nested map operators.
I wanted to refresh some recursion stuffs and came out with a solution for you query.
const values = [{
id: "n1",
children: [{
id: "n10",
children: [{
id: "n100",
children: []
}, ]
},
{
id: "n11",
children: []
},
{
id: "n12",
children: []
}
]
}]
const getAllManagers = (employees) => {
return employees.reduce((acc, emp) => {
return acc.concat(emp.children.length > 0 ? [emp, ...getAllManagers(emp.children)] : [])
}, [])
}
const getAllNonManagers = (employees) => {
return employees.reduce((acc, emp) => {
return acc.concat(emp.children.length > 0 ? getAllNonManagers(emp.children) : emp)
}, [])
}
console.log("Managers: ", getAllManagers(values))
console.log("NonManagers:", getAllNonManagers(values))

convert nested object to one level up object in javascript

given json : -
{
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
}
desired json: -
{
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
I want to convert JSON with the help of lodash library of npm in javascript or suggest any other library,
it might be a silly question, Please explain it properly, I am a newbie in javascript and try to learn node.js. comment me if you need more explanation.
Thanks for help
You don't really need a library, you can just assign the property and delete the other.
However tokens is an array, which suggest there might be more than one. This will only take the first one (obj.tokens[0].token). Since objects can't have duplicate keys, you will only be able to have one token with your desired format (if that matters).
let obj = {
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
}
obj.token = obj.tokens[0].token
delete obj.tokens
console.log(obj)
There are a number of ways to solve this problem and no one "right" way. However, you may want to consider creating a new object, rather than mutating the original object. Objects are always passed by reference in JavaScript and it's easy to accidentally modify an object inside a function, not realizing that you just changed that object everywhere else it's referenced as well.
Since you mentioned it, here is a way to solve this with Lodash.
const obj = {
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
};
// create a new object without the tokens property
const newObj = _.omit(obj, 'tokens');
// get the first token object from the tokens array
const tokenObj = _.head(obj.tokens);
// get the token string from the token object, defaulting to empty string if not found
newObj.token = _.get(tokenObj, 'token', '');
console.log(newObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Lodash is a great library and used by many projects. It can be especially helpful for new developers. For example, _.head(arr) will return undefined if arr is undefined. However, arr[0] would crash in the same scenario.
Here's one way to solve it without a library.
const obj = {
"_id": "5c1c4b2defb4ab11f801f30d",
"name": "Ray15",
"email": "ray15#gmail.com",
"deviceToken": "dgtssgeegwes",
"deviceType": "IOS",
"tokens": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzFjNGIyZGVmYjRhYjExZjgwMWYzMGQiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ1MzU4MTI2fQ.YdK0MjOm7Lff22uTFITQdic0gKdMZRpsmRee-yejDpQ"
}
]
};
// create a copy of the original object.
// note that Object.assign will make a shallow copy of our object,
// so newObj.tokens will be a pointer to obj.tokens.
// in this instance, we don't care, as we are going to remove newObj.tokens anyway.
const newObj = Object.assign({}, obj);
// throw away the tokens property.
// OK to mutate newObj as we know it is not used anywhere else.
delete newObj.tokens;
// get the first token object from the tokens array.
// the (expectedArray || []) pattern ensures we have an array if obj.tokens is null or undefined.
const tokenObj = (obj.tokens || [])[0];
// get the token string from the token object.
// again, using the (expectedObject || {}) pattern in case tokenObj is null or undefined.
const token = (tokenObj || {}).token;
// create a new property called "token" on our newObj object.
// set it to our token value or an empty string if token is null or undefined.
newObj.token = token || '';
// of course, if you know the tokens array will always have a valid token object,
// you can simply use newObj.token = obj.tokens[0].token.
console.log(newObj);
Using destructuring assignment with "empty" representations of your types works nicely. transform produces a reliable output when tokens contains zero, one, or many { token: ... } values.
const emptyUser =
{ _id: 0, name: "", tokens: [] }
const emptyToken =
{ token: "" }
const toSingleTokenUser =
({ tokens: [ { token } = emptyToken ], ...u } = emptyUser) =>
({ ...u, token })
console .log
( toSingleTokenUser ({ _id: 1, name: "a", tokens: [ { token: "t" } ] })
// { _id: 1, name: "a", token: "t" }
, toSingleTokenUser ({ _id: 1, name: "a", tokens: [] })
// { _id: 1, name: "a", token: "" }
, toSingleTokenUser ({ _id: 1, name: "a", tokens: [ { token: "t1" }, { token: "t2" } ] })
// { _id: 1, name: "a", token: "t1" }
, toSingleTokenUser ({ foo: "bar", tokens: [ { token: "t" } ] })
// { foo: "bar", token: "t" }
)

Categories