What is the best practice for structuring the state object in Redux in relation to related objects.
Example:
User has-one Organisation
With the above schema, where we also have a list of organisations is the following example a good idea?
{
user: {
id: 1,
organisation_id: 3,
first_name: 'Andrew',
last_name: 'McLagan',
email: 'andrew#example.com',
organisation: {
name: 'Foo Bar Co.'
suburb: 'Booklyn',
phone: '123-123-000',
},
},
orgnaisations: [
{
id: 1,
name: 'Facebook'
suburb: 'Booklyn',
phone: '000-000-000',
},
{
id: 2,
name: 'Twitter'
suburb: 'Manhattan',
phone: '456-456-000',
},
{
id: 3,
name: 'Foo Bar Co.'
suburb: 'Booklyn',
phone: '123-123-000',
},
{
id: 4,
name: 'Some Org.'
suburb: 'Bronx',
phone: '642-642-000',
},
]
}
Or would it be better to access the users organisation by:
const organisation = state.organisations[user.organisation_id];
I think it is better to access the user organizations through their ID. Here is a possible way to organize your state:
{
user: {
id: 1,
first_name: 'Andrew',
last_name: 'McLagan',
email: 'andrew#example.com',
organization: 3,
},
organizations: {
1: {id: 1, name: 'Facebook', suburb: 'Booklyn', phone: '000-000-000',},
2: {id: 2, name: 'Twitter', suburb: 'Manhattan', phone: '456-456-000'},
3: {id: 3, name: 'Foo Bar Co.', suburb: 'Booklyn', phone: '123-123-000'},
4: {id: 4, name: 'Some Org.', suburb: 'Bronx', phone: '642-642-000'},
}
}
Using vanilla Redux
If you want to get the current user and his organization, you can use the following selector:
function mapStateToProps(state) {
return {
user: state.user,
organization: state.organizations[state.user.organization]
}
}
The direct access using its ID will be a performance win. You can still easily query all stored organizations:
function mapStateToProps(state) {
return {
organizations: Object.values(state.organizations),
}
}
Using reselect
If you care about performance, using reselect would be a huge win. The first step is to define your selectors:
// Get a list of all organizations
const getAllOrganizations = createSelector(
state => state.organizations,
orgs => Object.values(orgs)
)
// Get the current user
const getUser = state => state.user
// Get the current user's organization
const getUserOrganization = createSelector(
[
state => state.user,
state => state.organizations,
],
(user, orgs) => orgs[user.organization],
)
You could now use those selectors to update your mapStateToProps functions. The two described above would be:
// Get the current user and his organization
function mapStateToProps(state) {
return {
user: getUser(state),
organization: getUserOrganization(state),
}
}
// Get all organizations
const mapStateToProps = getAllOrganizations
Related
I have a prisma query that returns users on a pivot table CommunityMember. The pivot table associates to the table User. As a result, my queries into the User table do not place the object user on top of the replies. I have a lot of functions designed to run with the user object on top so I am trying to figure out how to map user into my returns so the functions can run correctly. I've tried a lot of combinations of map and have had no luck. Do you all have any ideas?
Here is my prisma query:
members = await prisma.user.findMany({
select: {
id: true,
username: true,
name: true,
bio: true,
avatar: true,
},
skip: 10 * Number(page),
take: 10,
});
It gives a result like
members:
[{id: 2, username: 'man}, {id: 3, username: 'dan'}]
I want it to look like: members:
members:
[{user: {id: 2, username: 'man'}}, {user: {id: 3. username: 'dan'}}]
If I run members[0].user I should get the data inside. It seems like a simple map function, but I have not been able to get it to work.
Another example of what I get, but do not want.
members: [
{
id: 2,
username: 'man',
name: 'A Man',
bio: 'A man.',
avatar: [Object]
},
{
id: 3,
username: 'dude',
name: 'Dude',
bio: "Dude is a #1 developer.",
avatar: [Object]
},
This is what I want.
members: [
{
//Notice the user object on top of each entry
user: {
id: 2,
username: 'man',
name: 'A Man',
bio: 'Man.',
avatar: [Object]
}
},
{
user: {
id: 3,
username: 'dude',
name: 'Dude',
bio: "Dudes a #1 developer.",
avatar: [Object]
}
},
]
Not sure I got the whole picture but wouldn't this do?
const members = [
{
id: 2,
username: 'man',
name: 'A Man',
bio: 'A man.',
avatar: {}
},
{
id: 3,
username: 'dude',
name: 'Dude',
bio: "Dude is a #1 developer.",
avatar: {}
}
].map(member => ({user: member}))
if your object looks like:
obj = {members: [{...}, ..]}
then an Array.map will solve the problem:
const userMembers = obj.members.map((member) => ({user: member});
obj.members = userMembers;
In a project I'm working on, I need to merge 2 arrays of objects and as a result one new array of objects containing the merged key/values where two Ids match.
To give an example I created the following snippet but is not fully correct on what I want to achieve. More details after the snippet
const users = [{
id: 'Ae7uWu7LjwoEgVqzFU5xc',
firstName: 'Carl',
lastName: 'Jones'
},
{
id: 't2wzj8dh4r-qw1_SW-IOE',
firstName: 'Chloe',
lastName: 'Kearney'
},
{
id: '50Zwvw37OejbQBG7csZWJ',
firstName: 'Gemma',
lastName: 'Sloan'
},
{
id: 'NpcXdEKqfzhVCZOJ1dKuw',
firstName: 'Dario',
lastName: 'Angelini'
},
{
id: 'e95ZG9IfV442HdJp-CaBL',
firstName: 'Mindy',
lastName: 'Schreiber'
},
{
id: 'eAMv8AbynYRkdBPE5Scm2',
firstName: 'Xdax',
lastName: 'Rufq'
},
{
id: 'egMXnFvoMM7f4in3Se4Ui',
firstName: 'Mtajx',
lastName: 'Plde'
},
{
id: '6kbPT-HC5-szACuJ85I6r',
firstName: 'Zsofi',
lastName: 'Toke'
}
]
const comments = [{
content: 'Patient follow up call scheduled for 11Nov2021 at 8am',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:11.780Z'
},
{
content: 'Patient confirmed GP referral on [date]',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:42.237Z'
},
{
content: 'Candidate called on [date] and visit scheduled for [date] ',
stage: 'AT_SITE',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:43:42.140Z'
},
{
content: 'Candidate test result was positive for Pompe disease on [date]',
stage: 'AT_SITE',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:45:21.716Z'
}
]
const result = users.map(t1 => ({
...t1,
content: comments.filter(t2 => t2.userId === t1.id).map(t1 => t1.content),
created: comments.filter(t2 => t2.userId === t1.id).map(t1 => t1.createdAt),
}));
console.log(result)
The result I was able to get from that try was an array of objects but the comments are represented as an array inside the user object itself as for the createdAt
this is an example of what I'm getting now
[{
"id": "t2wzj8dh4r-qw1_SW-IOE",
"firstName": "Chloe",
"lastName": "Kearney",
"content": [
"Patient follow up call scheduled for 11Nov2021 at 8am",
"Patient confirmed GP referral on [date]",
"Candidate called on [date] and visit scheduled for [date] ",
"Candidate test result was positive for Pompe disease on [date]"
],
"created": [
"2021-10-29T11:41:11.780Z",
"2021-10-29T11:41:42.237Z",
"2021-10-29T11:43:42.140Z",
"2021-10-29T11:45:21.716Z"
]
},]
What I would like to get is the way around, I mean I want the comments to include the
firstName and lastName of the user when the comments.userId is equal to the users.id
Example of the goal I want to achieve
consider the 2 objects below
comments = [{
content: 'Patient follow up call scheduled for 11Nov2021 at 8am',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:11.780Z'
},
{
content: 'Patient confirmed GP referral on [date]',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:42.237Z'
}, { ...some other comments...}]
users = [
{
id: 't2wzj8dh4r-qw1_SW-IOE',
firstName: 'Chloe',
lastName: 'Kearney'
},
{ ...some other users... }]
The result I'm seeking after the 2 objects are merged is as follows
res = [
{
firstName: 'Chloe',
lastName: 'Kearney',
content: 'Patient follow up call scheduled for 11Nov2021 at 8am',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:11.780Z'
},
{
firstName: 'Chloe',
lastName: 'Kearney',
content: 'Patient confirmed GP referral on [date]',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:42.237Z'
}
]
As above I'm adding the first and last name of the user with the comments where there is an Ids match, so they are together after the merging.
I'm looking to understand a good way of doing this
const comments = [{
content: 'Patient follow up call scheduled for 11Nov2021 at 8am',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:11.780Z'
},{
content: 'Patient confirmed GP referral on [date]',
stage: 'AT_CALLCENTER',
userId: 't2wzj8dh4r-qw1_SW-IOE',
createdAt: '2021-10-29T11:41:42.237Z'
}];
const users = [{
id: 't2wzj8dh4r-qw1_SW-IOE',
firstName: 'Chloe',
lastName: 'Kearney'
}];
console.log(
comments.map(comment => {
const {id, ...user} = users.find(({id}) => id===comment.userId);
return ({...user, ...comment});
}));
I have a sample data object below, and I want to get the expected output data.
I have research and end to these sites but I'm having difficutly to apply it. related-link1 related-link2
Someone knows how to do it in a shortest way as possible? thanks
My sample data:
[
{
id: 1,
username: user_1,
user: {
name: 'Cuppelo'
}
},
{
id: 2,
username: user_2,
user: {
name: 'John'
}
},
{
id: 3,
username: user_3,
user: {
name: 'Jane'
}
}
]
Expected output: ['Cuppelo', 'John', 'Jane']
Assuming the sample data array is saved to variable users, the following would give you a new array that matches your expected output:
users.map(ea => ea.user.name);
Use Array.map
const user_1 = 'something';
const user_2 = 'something';
const user_3 = 'something';
const arr_1 = [
{
id: 1,
username: user_1,
user: {
name: 'Cuppelo'
}
},
{
id: 2,
username: user_2,
user: {
name: 'John'
}
},
{
id: 3,
username: user_3,
user: {
name: 'Jane'
}
}
];
const arr_2 = arr_1.map(obj => obj.user.name);
console.log(arr_2);
I am getting below JSON response:
users: {
1: {
name: "John",
email: "john#test.com",
id: 1,
place: "NY"
},
2: {
name: "Alex",
email: "alex#test.com",
id: 2,
place: "FL"
},
3: {
name: "Tony",
email: "tony#test.com",
id: 3,
place: "TX"
}
.
.
.
.
.
.
}
I want to swap the id key with email key from the inner object value as below format.
users: {
"john#test.com": {
name: "John",
email: "john#test.com",
id: 1,
place: "NY"
},
}
I am using below lodash code to make it work and its working fine:
_.keyBy(_.values(data), 'email');
Is there a better way I can handle it with lodash? I am new to lodash and I wanted to understand whether the code can be refactored further.
See _.keyBy() accepts a collection (an array or an object), you can skip the _.values() call:
const users = {"1":{"name":"John","email":"john#test.com","id":1,"place":"NY"},"2":{"name":"Alex","email":"alex#test.com","id":2,"place":"FL"},"3":{"name":"Tony","email":"tony#test.com","id":3,"place":"TX"}};
const result = _.keyBy(users, 'email');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
If you are looking for Vanilla JavaScript solution you can use array#reduce like this:
users = {
1: {
name: "John",
email: "john#test.com",
id: 1,
place: "NY"
},
2: {
name: "Alex",
email: "alex#test.com",
id: 2,
place: "FL"
},
3: {
name: "Tony",
email: "tony#test.com",
id: 3,
place: "TX"
}
}
let newUsers = Object.keys(users).reduce((obj, key) => {
obj[users[key].email] = users[key];
return obj;
}, {});
console.log(newUsers);
An example will speak for itself :
Array of Object :
[{
userId: 'ab4e3870-287e-11e7-b5a1-abb6183e9866',
email: 'email1#hotmail.com'
},{
userId: 'ae149220-2883-11e7-bbf9-1fb134f2b4ad',
email: 'email2#hotmail.com'
}]
Object
{
'ab4e3870-287e-11e7-b5a1-abb6183e9866': { name: 'john', roles: 'detective'},
'ae149220-2883-11e7-bbf9-1fb134f2b4ad': { name: 'james', roles: 'plumber'},
}
The result i'd like would be :
[{
userId: 'ab4e3870-287e-11e7-b5a1-abb6183e9866',
email: 'email1#hotmail.com',
name: 'john',
roles: 'detective'
},{
userId: 'ae149220-2883-11e7-bbf9-1fb134f2b4ad',
email: 'email2#hotmail.com',
name: 'james',
roles: 'plumber'
}]
So basically, the value of the key that match the userId in Object is added to that object in the array.
Is there some simple way I don't see to do that? Without external libraries in ES6?
var data = [{
userId: 'ab4e3870-287e-11e7-b5a1-abb6183e9866',
email: 'email1#hotmail.com'
},{
userId: 'ae149220-2883-11e7-bbf9-1fb134f2b4ad',
email: 'email2#hotmail.com'
}]
var d = {
'ab4e3870-287e-11e7-b5a1-abb6183e9866': { name: 'john', roles: 'detective'},
'ae149220-2883-11e7-bbf9-1fb134f2b4ad': { name: 'james', roles: 'plumber'},
};
Using ES6 spread operator ...
data = data.map(function(item) {
return {...item, ...d[item.userId]}
});
ES5: By adding properties manually
data = data.map(function(item) {
item.name = d[item.userId].name;
item.roles = d[item.userId].roles;
return item;
});