Getting undefined result when trying to loop and filtering array - javascript

I am currently working with objects and arrays in nodejs in conjuction with filters. I am currenlty facing difficulty in figuring out how to properly traverse an object and filter for the desired results. Instead I am getting undefined. I have an object users and I am wanting to filter for each user configuration that has active === true and then ultimately display every users configuration with that filter in the final result. What is the right/best way to approach this? Should I use map?
Current Result:
undefined
Desired Result:
[
{
email: 'test1#email.com',
active: true
},
{
email: 'test3#email.com',
active: true
},
{
email: 'test4#email.com',
active: true
}
]
Code:
const users = [
{
name: 'User1',
configuration: [
{
email: 'test1#email.com',
active: true
},
{
email: 'test2#email.com',
active: false
}
],
},
{
name: 'User2',
configuration: [
{
email: 'test3#email.com',
active: true
},
{
email: 'test4#email.com',
active: true
}
],
},
];
const result = users.forEach(user => user.configuration.filter( x => {
let {
active
} = x;
return active === true;
}));
console.log(result);

you can use flatMap for this. forEach always returns undefined. usually if you want to return some array use map but since filter also returns an array you need to flat it to get your desired result hence flatMap
const users = [{name: 'User1',configuration: [ {email: 'test1#email.com',active: true},{email: 'test2#email.com',active: false}],},{name: 'User2',configuration: [ {email: 'test3#email.com',active: true},{email: 'test4#email.com',active: true}],},];
const result = users.flatMap(user => user.configuration.filter( x => x.active===true));
console.log(result);

Related

Node Js how to fetch data from database in an hierarchical way

I'm writing a back code using NodeJs to fetch some data from backend, I want dataBase data to be like this
like this:
data = [{
name: "Admin",
id: '1',
children: [
{ name: "Admin", id: "1" },
{ name: "groupe1", id: "2" },
{
name: "groupe2", id: "1455", children: [
{ name: "groupe2", id: "1455" },
{ name: "gro", id: "5444" },
{ name: "hhrr", id: "45" }
]
}
]
}]
the idea is simple we have a list of group each group has a parent I want to display all the groups list in an hierarchical way the top one of the tree is done
Some groups are parents and groups in the same time and some others are only groups if the group is not parent we add an object with its name and ID in the array of children of his parent
if this groups is a parent that's mean it has children we add an object with its ID and name in the array of children of his parents, and we add property children for the object which is array named children with for the first time an object with the name and the id of the group etc...
i tryed to do this but it did not work
const getParentsByType = async ({ name, _id }) => {
let parentResult = [
{
id: _id,
name: name,
children: [
{
id: _id,
name: name,
},
],
},
];
parentResult= await findParent(_id, parentResult[0].children, 0);
return parentResult;
};
const findParent = async (parentId, parentResult, itemPos) => {
let children = await Models.GroupModel.find({ parent: parentId, status: true }).select('name _id');
for (let i = 0; i < children.length; i++) {
let childrenList = await Models.GroupModel.find({ parent: children[i]._id, status: true }).select('name _id');
if (childrenList.length != 0) {
parentResult.push(buildParentWithChild(children[i]._id, children[i].name));
findParent(children[i]._id,parentResult.children[i],itemPos++)
} else {
parentResult.push(buildParent(children[i]._id, children[i].name));
}
}
return parentResult
};
and this the model of the data base
const Group = mongoose.Schema({
name: {
type: String,
required: true,
},
status: {
type: Boolean,
required: true,
},
parent: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Group',
},
});
i had two days trying to resolve tis but with no result
i need some helps and Thank you
Try parsing your returned data. It validates your data as objects i dont see any problem with your function regardless i still have no idea what format your a trying to build.
let children = JSON.parse(JSON.stringify(await Models.GroupModel.find({ parent: parentId, status: true }).select('name _id')));
let childrenList = JSON.parse(JSON.stringify(await Models.GroupModel.find({ parent: children[i]._id, status: true }).select('name _id')));
If I understand you right, you want to convert the array returned by Models.GroupModel.find, and which looks like
var dbresult = [
{_id: "1", parent: null, name: "one"},
{_id: "2", parent: "1", name: "two"}
];
into a hierarchical structure. This can be done with a function that adds all children of a given parent p, including, recursively, their children. Like the following:
function children(p) {
var result = [];
for (r of dbresult) if (r.parent === p) {
var row = {_id: r._id, name: r.name};
var chld = children(r._id);
if (chld.length > 0) row.children = chld;
result.push(row);
}
return result;
}
console.log(JSON.stringify(children(null)));
Note that this approach requires only one database access (to fill the dbresult) and is therefore probably faster than your findParent function.

Comparing two arrays with field in common then pushing to a new array with corresponding grouped fields

general programming problem here.
I have this array called SPACES
[
{
_id: 5e1c4689429a8a0decf16f69,
challengers: [
5dfa24dce9cbc0180fb60226,
5dfa26f46719311869ac1756,
5dfa270c6719311869ac1757
]
},
{
_id: 5e1c4eb9c9461510407d5e81,
challengers: [ 5dfa24dce9cbc0180fb60226, 5dfa26f46719311869ac1756 ],
}
]
And this array called USERS
[
{
_id: 5dfa24dce9cbc0180fb60226,
name: 'Account 1',
email: 'account1#gmail.com',
spaces: [ 5e1c4689429a8a0decf16f69, 5e1c4eb9c9461510407d5e81 ],
},
{
_id: 5dfa26f46719311869ac1756,
name: 'Account 2',
email: 'account2#gmail.com',
spaces: [ 5e1c4689429a8a0decf16f69, 5e1c4eb9c9461510407d5e81 ]
},
{
_id: 5dfa270c6719311869ac1757,
name: 'Account 3',
email: 'account3#gmail.com',
spaces: [ 5e1c4689429a8a0decf16f69 ]
}
]
What I want to do, is go through both, and instead of having the SPACES.challengers array be just IDS, I would like the array to contain each USER object.
So for example, if the USER has an ID that is inside the SPACES.challengers array, then push the user into that array (which will then be the entire object).
SO FAR I have tried this (I am not very good yet):
users.map( ( user ) => {
spaces.map( ( space ) => {
if ( user.spaces.includes( space._id ) ) {
space.challengers.push(user)
}
} );
} );
However, I am not getting inside the IF block. (Even if I did, not sure if it would work OR if this is even how to do it). It feels Odd doing double maps, as I get so many iterations, and it duplicates my push (cause I have no logic to see if it just has been pushed).
Assuming every entry in the Users array has a unique ID, we can build a Hashmap to store (id, index) pairs in order to search efficiently for an ID from Users array while looping through Spaces array.
let spaces = [{_id: '5e1c4689429a8a0decf16f69',challengers: ['5dfa24dce9cbc0180fb60226', '5dfa26f46719311869ac1756', '5dfa270c6719311869ac1757']},{_id: '5e1c4eb9c9461510407d5e81',challengers: [ '5dfa24dce9cbc0180fb60226', '5dfa26f46719311869ac1756' ],}]
let users = [{_id: '5dfa24dce9cbc0180fb60226',name: 'Account 1',email: 'account1#gmail.com',spaces: [ '5e1c4689429a8a0decf16f69', '5e1c4eb9c9461510407d5e81' ],},{_id: '5dfa26f46719311869ac1756',name: 'Account 2',email: 'account2#gmail.com',spaces: [ '5e1c4689429a8a0decf16f69', '5e1c4eb9c9461510407d5e81' ]},{_id: '5dfa270c6719311869ac1757',name: 'Account 3',email: 'account3#gmail.com',spaces: [ '5e1c4689429a8a0decf16f69' ]}]
let IDIndexMapping = {} // To store (_id, index) pairs, in order to improve search efficiency
for(let index in users) // Iterate through Users array using index
IDIndexMapping[users[index]._id] = index; // store (_id, index) pair in IDIndexMapping
// I'm avoiding using `map` and using vanilla `for` loop for space efficiency
// as map returns a new array but with `for` loop, we can perform changes in-place
for(let outerIndex in spaces){ // Iterate through `spaces` array using index
let challengers = spaces[outerIndex].challengers; // Get challengers array
for(let innerIndex in challengers){ // Iterate through challengers array using index
let ID = challengers[innerIndex]; // Get ID
if(ID in IDIndexMapping) // If ID exists in IDIndexMapping
spaces[outerIndex].challengers[innerIndex] = users[IDIndexMapping[ID]]; // Change ID to actual User object
}
}
console.log(spaces)
Output
[ { _id: '5e1c4689429a8a0decf16f69',
challengers: [ [Object], [Object], [Object] ] },
{ _id: '5e1c4eb9c9461510407d5e81',
challengers: [ [Object], [Object] ] } ]
.map and .find should work here. keep it simple.
var spaces = [
{
_id: "5e1c4689429a8a0decf16f69",
challengers: [
"5dfa24dce9cbc0180fb60226",
"5dfa26f46719311869ac1756",
"5dfa270c6719311869ac1757"
]
},
{
_id: "5e1c4eb9c9461510407d5e81",
challengers: ["5dfa24dce9cbc0180fb60226", "5dfa26f46719311869ac1756", "some non existent"]
}
],
users = [
{
_id: "5dfa24dce9cbc0180fb60226",
name: "Account 1",
email: "account1#gmail.com",
spaces: ["5e1c4689429a8a0decf16f69", "5e1c4eb9c9461510407d5e81"]
},
{
_id: "5dfa26f46719311869ac1756",
name: "Account 2",
email: "account2#gmail.com",
spaces: ["5e1c4689429a8a0decf16f69", "5e1c4eb9c9461510407d5e81"]
},
{
_id: "5dfa270c6719311869ac1757",
name: "Account 3",
email: "account3#gmail.com",
spaces: ["5e1c4689429a8a0decf16f69"]
}
],
result = spaces.map(({ _id, challengers }) => ({
_id,
challengers: challengers.map(challenger =>
users.find(user => user._id === challenger)
).filter(row => row)
}));
console.log(JSON.stringify(result, null, 2));
You can create a map of challengers for look-up and then put them in spaces.
//create user map for look-up
userMap = users.reduce((res, val) => ({
...res,
[val._id]: val
}), {});
//change challenger id with user object
inflatedSpaces = spaces.map(s => ({ ...s, challengers: s.challengers.map(c => userMap[c]) }));
You could map the users with a Map.
Beside the destructuring of the object for mapping this answer uses for this part
challengers: challengers.map(
Map.prototype.get, // cb with a prototype and using `this`
new Map(users.map(o => [o._id, o])) // thisArg
)
the above mentioned Map in two parts.
The lower part generates an instance of Map where _id of the users items is used as key and the whole object as value. This instance is uses as thisArg of Array#map, the second parameter.
The upper part is a prototype of Map, used as callback. And while an this object is supplied, a binding (Function#bind) is not necessary.
var spaces = [{ _id: '5e1c4689429a8a0decf16f69', challengers: ['5dfa24dce9cbc0180fb60226', '5dfa26f46719311869ac1756', '5dfa270c6719311869ac1757'] }, { _id: '5e1c4eb9c9461510407d5e81', challengers: ['5dfa24dce9cbc0180fb60226', '5dfa26f46719311869ac1756'] }],
users = [{ _id: '5dfa24dce9cbc0180fb60226', name: 'Account 1', email: 'account1#gmail.com', spaces: ['5e1c4689429a8a0decf16f69', '5e1c4eb9c9461510407d5e81'] }, { _id: '5dfa26f46719311869ac1756', name: 'Account 2', email: 'account2#gmail.com', spaces: ['5e1c4689429a8a0decf16f69', '5e1c4eb9c9461510407d5e81'] },{ _id: '5dfa270c6719311869ac1757', name: 'Account 3', email: 'account3#gmail.com', spaces: ['5e1c4689429a8a0decf16f69'] }],
result = spaces.map(({ _id, challengers }) => ({
_id,
challengers: challengers.map(
Map.prototype.get,
new Map(users.map(o => [o._id, o]))
)
}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Combine several objects with weird structure into one

I have an array with a few objects which I'm trying to combine into one single object
[
{ user: { '563D': { pId: '12', seasion: '120', value: true } } },
{ user: { '563D': { pId: '11', seasion: '120', value: false } } },
...
]
pId is unique
seasion is the same for each object (almost never changing)
value can be anything
I want to have something like this:
{
id: '563D',
seasion: '120',
types: {
12: // pId
{
value: true
},
11:
{
value: false
}
}
}
I tried to use reduce and forEach but I wasnt been able to achieve my goals
due to poor understanding of those 2 methods.
EDIT:
forgot about several users input, sorry
[
{
users: {
'563D': [Object],
'4b07': [Object]
}
},
{
users: {
'563D': [Object],
'4b07': [Object]
}
},
{
users: {
'563D': [Object],
'4b07': [Object]
}
}
]
You could use reduce and destructuring to group the objects based on the first key inside user. Then use Object.values() to get the array of each group values:
Get user from each object by destructuring the parameter
Destructure the first entry of the user to get the key (like '563D') and the nested properties separately)
Use the || operator to check if the accumulator already has the id as it's property. If yes, use it. Else assign a new value with { id, seasion, types: {} }. This is using the Shorthand property names.
Update the types with pId as key and { value } as it's value
const input = [{user:{'563D':{pId:'12',seasion:120,value:true}, '4b07':{pId:'12',seasion:120,value:true}}},{user:{'563D':{pId:'11',seasion:120,value:false},'4b07':{pId:'11',seasion:120,value:false}}}]
const output = input.reduce((r, { user }) => {
for(const [id, { pId, seasion, value }] of Object.entries(user)) {
r[id] = r[id] || { id, seasion, types: {} };
r[id].types[pId] = { value };
}
return r;
}, {})
console.log(Object.values(output))
If you have only one unique id in the array, you can simplify the reduce to:
const input = [{user:{'563D':{pId:'12',seasion:120,value:true}}},{user:{'563D':{pId:'11',seasion:120,value:false}}}]
const output = input.reduce((r, { user }) => {
const [id, { pId, seasion, value }] = Object.entries(user)[0];
return { id, seasion, types: { ...r.types, [pId]: { value } } }
}, {})
console.log(output)

javascript remove using reduce

I'm trying to just get particular values in an obj with the status of 'xyz'
user.friends =
CoreMongooseArray [
{ _id: 5b11824350c0011afe9ca310,
user:
{ profile: [Object],
_id: 5b11805a50c0011afe9ca2fe,
username: 'user1' },
status: 'abc' },
{ _id: 5b191033d240ab4a10ffb54f,
user:
{ profile: [Object],
_id: 5b0ec81f958f5b4919b83c40,
username: 'user2' },
status: 'xyz' } ]
I'm using
user.friends.reduce((a, t) => a + (t.type === 'xyz' ? 0 : 1), 0);
but it only returns 1, rather than just the object with the username user2, why?
but it only returns 1, rather than just the object with the username user2, why?
Because that's the last return value of your callback. This is how reduce works.
If you want to find one particular object in an array matching a criterion, reduce isn't the tool to use (though you could force it to work, just as you can use a screwdriver as a hammer if you try hard enough). The tool to use is find:
const oneXYZFriend = user.friends.find(e => e.status === 'xyz');
(Notice I changed the test from e.type === 'xyz' to e.status === 'xyz', since your objects have a status property, not a type property.)
If you want to find several objects in an array matching a criterion, you'd use filter:
const xyzFriends = user.friends.filter(e => e.status === 'xyz');

javascript (reactJS) best way to access values in a child Array

I've got the following array:
This is an array of Users, and each User has an Attributes array.
Now I want to make a new array with users and only their attributes. Like this
users{
0: {
"phone_number",
"email"
}
}
What would be the best way to achieve this?
thanks
If you need Array of users which contains arrays with users attributes, then you can use Array.prototype.map method:
let users = [
{ Attributes: [ { Name: 'phone_number' }, { Name: 'email' } ] },
{ Attributes: [ { Name: 'phone_number1' }, { Name: 'email1' } ] }
];
let result = users.map((user) => user.Attributes.map((attr) => attr.Name));
console.log(result)

Categories

Resources