Map array and group by roles in the array object - javascript

I have an object array, And in that I have roles as a key, And values init.
Now what I want is I want to group them as per the roles.
This is my data input
{
users: [
{
firstName: 'Will',
lastName: 'Jacob',
email: 'sample#sample.com',
_id: '5e324187b5fdf167a91dfdbb',
roles: [ 'ward', 'hospital', 'hr' ],
},
{
firstName: 'Theatre',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf2f0c631a8788be59fc4',
roles: [ 'ward' ],
},
{
firstName: 'Cinema',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema2',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['ward', 'hr' ],
},
{
firstName: 'Cinema3',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema4',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: [ 'ward', 'hospital', 'hr' ],
}
]}
AND I want to group it by roles in them and want output something like below
{
ward: [{
firstName: 'Will',
lastName: 'Jacob',
email: 'sample#sample.com',
_id: '5e324187b5fdf167a91dfdbb',
roles: [ 'ward', 'hospital', 'hr' ],
},
{
firstName: 'Theatre',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf2f0c631a8788be59fc4',
roles: [ 'ward' ],
},
{
firstName: 'Cinema2',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['ward', 'hr' ],
},
{
firstName: 'Cinema3',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: [ 'ward', 'hospital', 'hr' ],
}],
hospital: [
{
firstName: 'Will',
lastName: 'Jacob',
email: 'sample#sample.com',
_id: '5e324187b5fdf167a91dfdbb',
roles: [ 'ward', 'hospital', 'hr' ],
},
{
firstName: 'Cinema',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema3',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema4',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: [ 'ward', 'hospital', 'hr' ],
}],
hr: [{
firstName: 'Will',
lastName: 'Jacob',
email: 'sample#sample.com',
_id: '5e324187b5fdf167a91dfdbb',
roles: [ 'ward', 'hospital', 'hr' ],
},
{
firstName: 'Cinema',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema2',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['ward', 'hr' ],
},
{
firstName: 'Cinema3',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema4',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: [ 'ward', 'hospital', 'hr' ],
}
]
}
How can I achieve this? I am looking for a function to process this and return the output as requried.

Please find the Array.reduce implementation.
Logic
Loop through each object in array
Loop through the roles array in each object.
Check if the accumulator have a node with that role, if yes push to that node in accumulator, or else create a node with that name and current object as an element of that node
Working Example
const data = {"users":[{"firstName":"Will","lastName":"Jacob","email":"sample#sample.com","_id":"5e324187b5fdf167a91dfdbb","roles":["ward","hospital","hr"]},{"firstName":"Theatre","lastName":"Manager","email":"sample#sample.com","_id":"5e3cf2f0c631a8788be59fc4","roles":["ward"]},{"firstName":"Cinema","lastName":"Manager","email":"sample#sample.com","_id":"5e3cf62cc631a8788be59fc5","roles":["hospital","hr"]},{"firstName":"Cinema2","lastName":"Manager","email":"sample#sample.com","_id":"5e3cf62cc631a8788be59fc5","roles":["ward","hr"]},{"firstName":"Cinema3","lastName":"Manager","email":"sample#sample.com","_id":"5e3cf62cc631a8788be59fc5","roles":["hospital","hr"]},{"firstName":"Cinema4","lastName":"Manager","email":"sample#sample.com","_id":"5e3cf62cc631a8788be59fc5","roles":["ward","hospital","hr"]}]};
const output = data.users.reduce((acc, curr) => {
curr.roles.forEach((role) => {
acc[role] ? acc[role].push(curr) : acc[role] = [curr];
})
return acc;
}, {});
console.log(output);

You can use array#reduce to group your data based on roles. You can iterate through each object and create separate array for each role type. This solution only require single traversal of your input array.
const input = { users: [ { firstName: 'Will', lastName: 'Jacob', email: 'sample#sample.com', _id: '5e324187b5fdf167a91dfdbb', roles: [ 'ward', 'hospital', 'hr' ], }, { firstName: 'Theatre', lastName: 'Manager', email: 'sample#sample.com', _id: '5e3cf2f0c631a8788be59fc4', roles: [ 'ward' ], }, { firstName: 'Cinema', lastName: 'Manager', email: 'sample#sample.com', _id: '5e3cf62cc631a8788be59fc5', roles: ['hospital', 'hr' ], }, { firstName: 'Cinema2', lastName: 'Manager', email: 'sample#sample.com', _id: '5e3cf62cc631a8788be59fc5', roles: ['ward', 'hr' ], }, { firstName: 'Cinema3', lastName: 'Manager', email: 'sample#sample.com', _id: '5e3cf62cc631a8788be59fc5', roles: ['hospital', 'hr' ], }, { firstName: 'Cinema4', lastName: 'Manager', email: 'sample#sample.com', _id: '5e3cf62cc631a8788be59fc5', roles: [ 'ward', 'hospital', 'hr' ], }]},
result = input.users.reduce((r, o) => {
o.roles.forEach(role => {
r[role] ??= [];
r[role].push(JSON.parse(JSON.stringify(o)));
});
return r;
},{});
console.log(result);

You can just go over each input element and then over each role in the input element and add the element to the corresponding array in a by-role object (creating the array as needed):
const byRole = {}
for (const obj of input.users) {
for (const role of obj.roles) {
if (!byRole[role]) byRole[role] = []
byRole[role].push(obj)
}
}
console.log(byRole)
There would be also a less imperative, more functional approach, if you prefer that:
const byRole = Object.fromEntries(
[...new Set(input.users.map(obj => obj.roles).flat())]
.map(role => [role, inputArray.filter(obj => obj.roles.includes(role))])
)
console.log(byRole)
Since you seem to be working with MongoDB records, another possibility would be to group it already in your database query, offloading that work to the database server:
const queryResult = await db.users.aggregate([
// Optionally add a $match step here to filter: { $match: { ... } }
{ $addFields: { role: '$roles' } },
{ $unwind: '$role' },
{ $group: { _id: '$role', records: { $push: '$$ROOT' } } }
])
const byRole = Object.fromEntries(
queryResult.map(({ _id, records }) => [_id, records])
)
(This will leave an extra field role in each record though, but I guess you won't mind.)

Related

How to get data from an object

How to get data from an object? I need to get data from dataValues ​​and write it down
const user = User.findOne({
}).then(e=>console.log(e))
User {
dataValues: {
id: 1,
firstName: 'Мен',
lastName: 'Bezrukov',
login: 'qqq',
password: '1234',
role: 'admin',
ip: '12345',
descipt: 'developer',
o_sebe: 'top man',
soc_set: 'vk',
age: '17',
likes__foto: '5',
coment__foto: null,
createdAt: 2023-01-15T09:06:39.000Z,
updatedAt: 2023-01-15T09:07:00.000Z
},
_previousDataValues: {
id: 1,
firstName: 'Мен',
lastName: 'Bezrukov',
login: 'qqq',
password: '1234',
role: 'admin',
ip: '12345',
descipt: 'developer',
o_sebe: 'top man',
soc_set: 'vk',
age: '17',
likes__foto: '5',
coment__foto: null,
createdAt: 2023-01-15T09:06:39.000Z,
updatedAt: 2023-01-15T09:07:00.000Z
},
uniqno: 1,
_changed: Set(0) {},
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [
'id', 'firstName',
'lastName', 'login',
'password', 'role',
'ip', 'descipt',
'o_sebe', 'soc_set',
'age', 'likes__foto',
'coment__foto', 'createdAt',
'updatedAt'
]
},
}
You can access directly the data by user.id, user.firstName or destructuring:
const {id,firstName} = user
another options is putting raw: true.
User.findOne({ where: {firstname: "some name"},
raw: true
})
This gives you directly an object with only the data instead of an sequelize instance.

how to refactor array from array to single array using javascript

const arr = [
[
{
_id: "6136096f4255d84bcb4a7144",
user_id: "5fbfa729fc46a415ce5503a6",
picture: [Array],
timestamp: 1630931311227,
},
user: {
_id: "5fbfa729fc46a415ce5503a6",
first_name: "ABC",
last_name: "AAA",
picture: [Object]
}
],
[
{
_id: "613609414255d84bcb4a7122",
user_id: "5fbf6f91aff7f3320a906547",
picture: [Array],
device_platform: 'ios',
timestamp: 1630931265409
},
user: {
_id: "5fbf6f91aff7f3320a906547",
first_name: 'EEE',
last_name: 'TTT',
picture: [Object]
}
],
[
{
_id: "613709f49223350dfdaec618",
user_id: "5fbfa748fc46a415ce5503a8",
picture: [Array],
timestamp: 1630996980379
},
{
_id: "613609184255d84bcb4a710a",
user_id: "5fbfa748fc46a415ce5503a8",
picture: [Array],
timestamp: 1630931224383,
},
user: {
_id: "5fbfa748fc46a415ce5503a8",
first_name: 'GRT',
last_name: 'GGG',
picture: [Object]
}
]
]
I merged push into the object one were like res = [{_id: ..., user_id: ...},{_id: ..., user_id: ...}] and other one was like user = {_id: 5fbfa748fc46a415ce5503a8, first_name: 'AAA',last_name : 'DD'}
res.user = user;
array.push(res)
I merged two object it bring up this but it does not seems to be correct response.
when I used var merged = [].concat.apply([], arr); it does not work
how to fix with correct format.
Working code! just remove the user key from the array, and one note ) use const/let instead of var
const arr = [
[
{
_id: "6136096f4255d84bcb4a7144",
user_id: "5fbfa729fc46a415ce5503a6",
picture: [Array],
timestamp: 1630931311227,
},
{
_id: "5fbfa729fc46a415ce5503a6",
first_name: "ABC",
last_name: "AAA",
picture: [Object]
}
],
[
{
_id: "613609414255d84bcb4a7122",
user_id: "5fbf6f91aff7f3320a906547",
picture: [Array],
device_platform: 'ios',
timestamp: 1630931265409
},
{
_id: "5fbf6f91aff7f3320a906547",
first_name: 'EEE',
last_name: 'TTT',
picture: [Object]
}
],
[
{
_id: "613709f49223350dfdaec618",
user_id: "5fbfa748fc46a415ce5503a8",
picture: [Array],
timestamp: 1630996980379
},
{
_id: "613609184255d84bcb4a710a",
user_id: "5fbfa748fc46a415ce5503a8",
picture: [Array],
timestamp: 1630931224383,
},
{
_id: "5fbfa748fc46a415ce5503a8",
first_name: 'GRT',
last_name: 'GGG',
picture: [Object]
}
]
]
const merged = [].concat.apply([], arr);
console.log(merged);

Trying to write a function to determine if a complex object's deeply nested sub array has values

I'm trying to write a function to check a deeply nested sub array inside of a complex object to return true if it has values or false if it is empty but I'm not sure how to do this.
The section I'm trying to check is contacts inside each contactGroups section which is where I'm running into issues because the array is nested 4 levels down like object > array of objects > object > contacts array and I'm not sure how to map or iterate at that level.
This is my first pass at a function which is more pseudo code at this point:
const hasContacts = (contacts: {}) => {
if(contacts.contactGroups.length === 0
|| contacts.contactGroups.map((contact) => contactGroups.contacts === undefined
|| contacts.contactGroups.map((contact) => contactGroups.contacts.length === 0 ){
return false
}
return contacts
}
The data structure looks like this:
const mockContacts = {
count: 1,
contactGroups: [
{
contactGroup: "Family",
count: 2,
contacts: [
{
member: "Uncle",
fullName: "BENJAMIN BILLIARDS",
lastName: "BILLIARDS",
firstName: "BENJAMIN",
email: "shark#billiards.com",
},
{
member: "Aunt",
fullName: "DENISE NICE",
lastName: "NICE",
firstName: "DENISE",
email: "floral#flowers.com",
}
]
},
{
contactGroup: "Friends",
count: 2,
contacts: [
{
member: "School Friend",
fullName: "DERRICK SMITH",
lastName: "SMITH",
firstName: "DERRICK",
email: "smith978#gmail.com",
},
{
member: "Work Friend",
fullName: "TARA SKY",
lastName: "SKY",
firstName: "TARA",
email: "uptown94#gmail.com",
}
]
}
If you want to return boolean if there are any contacts then you can do the following:
const hasContacts = ({ contactGroups = [] } = []) =>
contactGroups.some(
({ contacts = [] } = {}) => contacts.length
);
console.log('pass undefined', hasContacts());
console.log('pass empty object', hasContacts({}));
console.log(
'pass empty contact group',
hasContacts({ contactGroups: [] })
);
console.log(
'pass empty contacts',
hasContacts({ contactGroups: [{ contacts: [] }] })
);
console.log(
'pass contacts',
hasContacts({ contactGroups: [{ contacts: [1] }] })
);
console.log(
'pass some contacts',
hasContacts({
contactGroups: [{ contacts: [] }, { contacts: [1] }],
})
);
const mockContacts = {
count: 1,
contactGroups: [
{
contactGroup: 'Family',
count: 2,
contacts: [
{
member: 'Uncle',
fullName: 'BENJAMIN BILLIARDS',
lastName: 'BILLIARDS',
firstName: 'BENJAMIN',
email: 'shark#billiards.com',
},
{
member: 'Aunt',
fullName: 'DENISE NICE',
lastName: 'NICE',
firstName: 'DENISE',
email: 'floral#flowers.com',
},
],
},
{
contactGroup: 'Friends',
count: 2,
contacts: [
{
member: 'School Friend',
fullName: 'DERRICK SMITH',
lastName: 'SMITH',
firstName: 'DERRICK',
email: 'smith978#gmail.com',
},
{
member: 'Work Friend',
fullName: 'TARA SKY',
lastName: 'SKY',
firstName: 'TARA',
email: 'uptown94#gmail.com',
},
],
},
],
};
console.log(
'mock contacts:',
hasContacts(mockContacts)
);
Assuming the nested contactGroup contacts cannot also have more nesting then this solution should work for you. I was unclear on how you wanted to handle each nested group so I returned an array that will tell you if each nested group does or does not have contacts.
const mockContacts = {
count: 1,
contactGroups: [
{
contactGroup: "Family",
count: 2,
contacts: [
{
member: "Uncle",
fullName: "BENJAMIN BILLIARDS",
lastName: "BILLIARDS",
firstName: "BENJAMIN",
email: "shark#billiards.com",
},
{
member: "Aunt",
fullName: "DENISE NICE",
lastName: "NICE",
firstName: "DENISE",
email: "floral#flowers.com",
}
]
},
{
contactGroup: "Friends",
count: 2,
contacts: [
{
member: "School Friend",
fullName: "DERRICK SMITH",
lastName: "SMITH",
firstName: "DERRICK",
email: "smith978#gmail.com",
},
{
member: "Work Friend",
fullName: "TARA SKY",
lastName: "SKY",
firstName: "TARA",
email: "uptown94#gmail.com",
}
]
}
]
}
const hasContacts = (contacts) => {
// if contacts is not undefined, then check contactGroup
if (contacts && Array.isArray(contacts.contactGroups)) {
// we can have more than one contact group so need to check each
return contacts.contactGroups.map(row=>Array.isArray(row.contacts) && row.contacts.length > 0)
}
}
console.log(hasContacts(mockContacts))

Using map function in Javascript to return new values

This is my json:
[ { gsm: 'gsm',
firstName: 'firstname',
lastName: 'lastname' },
{ gsm: '123456789',
firstName: 'Mohamed',
lastName: 'Sameer'},
{ gsm: '987654321',
firstName: 'Hameed',
lastName: 'Basha'}]
I want my final output looks like:
[ { gsm: 'gsm',
firstName: 'firstname',
lastName: 'lastname',
userKey: 'Key1'},
{ gsm: '123456789',
firstName: 'Mohamed',
lastName: 'Sameer',
userKey: 'Key1'},
{ gsm: '987654321',
firstName: 'Hameed',
lastName: 'Basha',
userKey: 'Key1'}]
i need to do this using any of the javascript methods like map...etc
Use map
var output = arr.map( s => ( s.userKey = "Key1", s ) );
Demo
var arr = [{
gsm: 'gsm',
firstName: 'firstname',
lastName: 'lastname'
},
{
gsm: '123456789',
firstName: 'Mohamed',
lastName: 'Sameer'
},
{
gsm: '987654321',
firstName: 'Hameed',
lastName: 'Basha'
}
];
var output = arr.map( s => ( s.userKey = "Key1", s ) );
console.log( output );
You could use Object.assign for generating a copy of the object and assign a new property and take Array#map for getting a new array.
var original = [ { gsm: 'gsm', firstName: 'firstname', lastName: 'lastname' }, { gsm: '123456789', firstName: 'Mohamed', lastName: 'Sameer' }, { gsm: '987654321', firstName: 'Hameed', lastName: 'Basha' }],
copy = original.map(o => Object.assign({}, o, { key: 'key1' }));
console.log(copy);
console.log(original);
.as-console-wrapper { max-height: 100% !important; top: 0; }
In case you don't want to mutate the original array:
const arr = [ { gsm: 'gsm',
firstName: 'firstname',
lastName: 'lastname' },
{ gsm: '123456789',
firstName: 'Mohamed',
lastName: 'Sameer'},
{ gsm: '987654321',
firstName: 'Hameed',
lastName: 'Basha'}]
const newArr = arr.map(item => ({
...item,
userKey: 'Key1',
}))
console.log(newArr)
You can do like this :)
var data = [ { gsm: 'gsm',
firstName: 'firstname',
lastName: 'lastname' },
{ gsm: '123456789',
firstName: 'Mohamed',
lastName: 'Sameer'},
{ gsm: '987654321',
firstName: 'Hameed',
lastName: 'Basha'}]
var finalarray = data.map(x => (x.userKey = 'Key1', x));
console.log(finalarray);
data.map(el => Object.assign(el, {userKey: 'Key1'}))
or
data.map(el => ({ ...el, userKey: 'Key1' }))

Why are these objects not equal?

I am trying to write a test in JavaScript using Mocha and Chai. At the end of the test, I want to compare 2 JavaScript objects, these should be equal.
The output I get from the test is the following:
{ publication:
{ publication_id: 'pubFetch1',
title: 'Publication Fetcher',
person_id: 'uploader',
URL: 'http://www.pubfetchertest.com',
publication_year: '2015',
upload_date: '2015-05-05 00:00:00',
page_count: '5',
type: 'paper',
rating: '0',
votes: '0',
abstract: 'Testing the Publication Fetcher',
location: 'location' },
comments:
[ { commentID: 'comment1',
personID: 'uploader',
firstName: 'First',
lastName: 'Last',
text: 'Comment Content',
time: '2015-05-05 10:24:36',
reactions: [],
myComment: true },
{ commentID: 'comment2',
personID: 'author1',
firstName: 'First',
lastName: 'Last',
text: 'Comment Content',
time: '2015-05-05 11:01:45',
reactions: [Object],
myComment: false } ],
keywords: [ 'keyword1', 'keyword2', 'keyword3' ],
uploader: { person_id: 'uploader', first_name: 'First', last_name: 'Last' },
score: 5,
authors:
[ { person_id: 'author1', first_name: 'First', last_name: 'Last' },
{ person_id: 'author2', first_name: 'First', last_name: 'Last' },
{ person_id: 'author3', first_name: 'First', last_name: 'Last' } ],
editors: [],
publishers: [] }
While the object I want to compare it with, is the following:
{ publication:
{ publication_id: 'pubFetch1',
title: 'Publication Fetcher',
person_id: 'uploader',
url: 'http://www.pubfetchertest.com',
publication_year: '2015',
upload_date: '2015-05-05 00:00:00',
page_count: '5',
type: 'paper',
rating: '0',
votes: '0',
abstract: 'Testing the Publication Fetcher',
location: 'location'},
comments:
[{ commentID: 'comment1',
personID: 'uploader',
firstName: 'First',
lastName: 'Last',
text: 'Comment Content',
time: '2015-05-05 10:24:36',
reactions: [],
myComment: true},
{ commentID: 'comment2',
personID: 'author1',
firstName: 'First',
lastName: 'Last',
text: 'Comment Content',
time: '2015-05-05 11:01:45',
reactions: [{ commentID: 'comment3',
personID: 'author2',
firstName: 'First',
lastName: 'Last',
text: 'Comment Content',
time: '2015-05-05 11:02:10',
reactions: [],
replyID: 'comment2',
myComment: false}],
myComment: false}],
keywords: ['keyword1', 'keyword2', 'keyword3'],
uploader: {person_id: 'uploader',
first_name: 'First',
last_name: 'Last'},
score: 5,
authors: [{person_id: 'author1',
first_name: 'First',
last_name: 'Last'},
{person_id: 'author2',
first_name: 'First',
last_name: 'Last'},
{person_id: 'author3',
first_name: 'First',
last_name: 'Last'}],
editors: [],
publishers: []
};
I don't see any difference in these 2 objects, so why does JavaScript say these are different? I am using JSON.stringify(obj1) === JSON.stringify(obj2) to compare these 2 objects.
JSFiddle: http://jsfiddle.net/9akeh8bh/4/
There are differences between the two objects; some keys have underscores and some are uppercase.
Have you tried standardising the key names and seeing if the comparison works?
Your reactions are different, some contain Objects, some do not.

Categories