How to map two array JSON to data in vue - javascript

I have JSON data that have two different arrays in one sheet.
I want to show each Organization Page then each page have every comment from the user who selects comment this organization.
{
ListOrg: {
id: 1613,
name_org: "US company",
rating: 0,
},
Review: [
{
review_id: 3,
org_id: 1613,
user_id: 2,
description: "Very good",
rating: 3,
user: {
id: 2,
name: "Kunjanaphorn",
firstname: "Kunjanaphorn",
lastname: "Boonmak",
admin: 0,
email: "Pim#gmail.com",
}
},
{
review_id: 4,
org_id: 1613,
user_id: 3,
description: "Not bad",
rating: 5,
user: {
id: 3,
name: "Kan",
firstname: "Kan",
lastname: "Tippayamontree",
admin: 0,
email: "First#gmail.com",
}
}
]
}
But I cannot map it to data in vue.js. I try this solution then it not work.
data() {
return {
Listorgs: [],
Reviews: [],
Listorg: {
name_org: "",
picture: "",
headerpic: "",
description: ""
}
mounted() {
axios.get("/api/listorgs/" + this.id).then(response => {
var listorg = response.data;
this.Reviews = listorg.Review;
this.Listorgs = listorg.Listorg;
});
}
Can you tell me about syntax
I want some attribute in each array -> name_org(string) from array ListOrg, description(string) from array Review, name(string) and firstname(string) from user array in Review array for show in vue page

I have helped you changed a little bit and made it work, check it out.
https://jsfiddle.net/fLvy3am9/
var listorg = response.data;
this.orgData = listorg.ListOrg;
this.reviews = listorg.Review.map((review) => {
return {
name_org: listorg.ListOrg.name_org,
description: review.description,
user: review.user
};
});
Ask me if there's any question.

Related

Why does this object contain `true` instead of the user name when logged?

I got an array with user info and user comments and I want to find which user left a specific comment. But when my function runs the console.log prints out this object:
{id: '7f053852-7440-4e44-838c-ddac24611050', firstName: false, lastName: 'Burke'}
and I’ve tried another comment but the results are not much different:
{id: 'b4a306cb-8b95-4f85-b9f8-434dbe010985', firstName: true, lastName: 'Marshall'}
Here my code:
var users = [
{
id: "88f24bea-3825-4237-a0d1-efb6b92d37a4",
firstName: "Sam",
lastName: "Hughes",
},
{
id: "2a35032d-e02b-4508-b3b5-6393aff75a53",
firstName: "Terri",
lastName: "Bishop",
},
{
id: "7f053852-7440-4e44-838c-ddac24611050",
firstName: "Jar",
lastName: "Burke",
},
{
id: "b4a306cb-8b95-4f85-b9f8-434dbe010985",
firstName: "Some string",
lastName: "Marshall"
}
];
const comments = [
{
userId: "88f24bea-3825-4237-a0d1-efb6b92d37a4",
text: "Great Job!"
},
{
userId: "7f053852-7440-4e44-838c-ddac24611050",
text: "Well done, I think I understand now!",
},
{
userId: "e789565f-fa5a-4d5e-8f6c-dd126cf995be",
text: "How do you do that? 😲",
},
{
userId: "7f053852-7440-4e44-838c-ddac24611050",
text: "OK great thanks"
},
{
userId: "b4a306cb-8b95-4f85-b9f8-434dbe010985",
text: "Cool, thanks!"
},
{
userId: "9e525c2d-6fcd-4d88-9ac4-a44eaf3a43e6",
text: "Nice one 😉"
}
];
var getuserbycom = users.find((user) => user.id === comments.find((comment) => comment.text === "Cool, thanks!").userId);
console.log(getuserbycom);
function findComment(comment) {
return comments.find(userComment => userComment.text === comment)
}
You will get the user Object. After that you can use the useId as required

Is there a neater way to transform an array of objects

I am trying to transform an array, with only one of the values changed. Is there a neater way to do it?
I have attached the code that I have tried. It works, however I am only changing the number of the contact object for each user so it feels a little redundant to go through every other value to create a new formatted array. How can I replace just the contact number without going through everything?
const users = [
{
id: "1",
name: {
givenNames: 'SpongeBob',
last: 'SquarePants',
},
contact: {
email: '',
phone: '+1 123-1231234'
},
},
{
id: "2",
name: {
givenNames: 'Patrick',
last: 'Star',
},
contact: {
email: 'test2#test.com',
phone: '+1 123-123-1234',
},
},
{
id: "3",
name: {
givenNames: 'Eugene Harold',
last: 'Krabs',
},
contact: {
email: 'test3#test.com',
phone: '',
},
},
];
My code:
guestList() {
const formattedArray = this.getSelectedGuests.map(user => {
var rObj = {};
rObj.id = user.id;
rObj.name = user.name;
rObj.contact = {
email: user.contact.email,
phone: user.contact.phone.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g, ''),
};
return rObj;
});
return formattedArray;
}
Output:
const users = [
{
id: "1",
name: {
givenNames: 'SpongeBob',
last: 'SquarePants',
},
contact: {
email: '',
phone: '11231231234'
},
},
{
id: "2",
name: {
givenNames: 'Patrick',
last: 'Star',
},
contact: {
email: 'test2#test.com',
phone: '11231231234',
},
},
{
id: "3",
name: {
givenNames: 'Eugene Harold',
last: 'Krabs',
},
contact: {
email: 'test3#test.com',
phone: '',
},
},
];
Since you only need to change a property inside contact, you can use object destructuring with rest, to extract contact from the rest of the object.
Now you can spread the rest of the object into the new one, create a new contact property, spread the contents of the original content into it, and override the phone property.
function guestList(getSelectedGuests) {
return getSelectedGuests.map(({ contact, ...rest }) => ({
...rest,
contacts: {
...contact,
phone: contact.phone.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g, ''),
}
}));
}
const users = [{"id":"1","name":{"givenNames":"SpongeBob","last":"SquarePants"},"contact":{"email":"","phone":"+1 123-1231234"}},{"id":"2","name":{"givenNames":"Patrick","last":"Star"},"contact":{"email":"test2#test.com","phone":"+1 123-123-1234"}},{"id":"3","name":{"givenNames":"Eugene Harold","last":"Krabs"},"contact":{"email":"test3#test.com","phone":""}}];
const result = guestList(users);
console.log(result);
If you need to do a lot of immutable transformations, you might want to consider Immer. Immer allows you to use simple mutating code, and it ensures immutability using Proxies.
const { produce } = immer;
function guestList(getSelectedGuests) {
return getSelectedGuests.map(user => produce(user, draft => {
draft.contact.phone = user.contact.phone.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g, '')
}));
}
const users = [{"id":"1","name":{"givenNames":"SpongeBob","last":"SquarePants"},"contact":{"email":"","phone":"+1 123-1231234"}},{"id":"2","name":{"givenNames":"Patrick","last":"Star"},"contact":{"email":"test2#test.com","phone":"+1 123-123-1234"}},{"id":"3","name":{"givenNames":"Eugene Harold","last":"Krabs"},"contact":{"email":"test3#test.com","phone":""}}];
const result = guestList(users);
console.log(result);
console.log(result[0] === users[0]); // false - a new object was created
<script src="https://unpkg.com/immer/dist/immer.umd.js"></script>
Well, as long as you don't use a library exposing Immutable objects implementation, this is the kind of code you have to write. Depending upon the JS dialect you have access to, you can write slightly shorter code, but the buld is still there:
guestList() {
return this.getSelectedGuests.map(user => ({
user.id,
user.name,
contact: {
user.contact.email,
phone: user.contact.phone.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g, ''),
}
}));
}
If you want to work with immutability, I would strongly advise to have a look at something like Immutable.js (probably the one with the most diffusion) or Seamless Immutable (which has far less diffusion, but I like it a lot).
You can't avoid visiting each user because you have to change each user's contact property.
I am only changing the number of the contact object for each user so
it feels a little redundant to go through every other value to create
a new formatted array.
You can use spread syntax to copy object properties without explicitly copying them.
I also added hyphen - and whitespace character \s to the regex to get the desired output.
const users = [{ id: "1", name: { givenNames: 'SpongeBob', last: 'SquarePants', }, contact: { email: '', phone: '+1 123-1231234' }, }, { id: "2", name: { givenNames: 'Patrick', last: 'Star', }, contact: { email: 'test2#test.com', phone: '+1 123-123-1234', }, }, { id: "3", name: { givenNames: 'Eugene Harold', last: 'Krabs', }, contact: { email: 'test3#test.com', phone: '', }, } ];
let result = users.map(user => ({
...user,
contact: {
...user.contact,
"phone": user.contact.phone.replace(/[&\/\\#,+()$~%.'":*?<>{}-\s]/g, '')
}
}));
console.log(result);
In most cases, you shouldn't be concerned about creating new arrays because JavaScript and platforms it runs on optimize for such scenarios.
But if you want to modify the array in-place, you can use forEach() to do that.
const users = [{ id: "1", name: { givenNames: 'SpongeBob', last: 'SquarePants', }, contact: { email: '', phone: '+1 123-1231234' }, }, { id: "2", name: { givenNames: 'Patrick', last: 'Star', }, contact: { email: 'test2#test.com', phone: '+1 123-123-1234', }, }, { id: "3", name: { givenNames: 'Eugene Harold', last: 'Krabs', }, contact: { email: 'test3#test.com', phone: '', }, } ];
users.forEach(user => {
user.contact.phone = user.contact.phone.replace(/[&\/\\#,+()$~%.'":*?<>{}-\s]/g, '');
});
console.log(users);

Retrieve a value from a Javascript object based on a match with a second attribute value

My apologies if this question has been asked many times before. I've searched Stackoverflow thoroughly and found nothing. It may be I was using the wrong search terms or didn't understand how the solutions given applied to my question.
I have two Javascript objects; pageviews and enrollments. Both contain data retrieved from a learning management system in separate API calls. Both objects contain a user_id attribute and some records in each object will have the same user_id values. How would I retrieve the value of enrollments.name when the values of pageviews.user_id and enrollments.user_id match?
var pageviews = [{
id: 1,
page: "Home",
user_id: "100032",
},
{
id: 2,
page: "Assignment 1",
user_id: "123032",
},
{
id: 3,
page: "Discussion 2",
user_id: "147032",
},
];
var enrollments = [{
id: 1,
name: "Amy",
role: "Student",
user_id: "100032",
},
{
id: 2,
name: "Bill",
role: "Teacher",
user_id: "123032",
},
{
id: 3,
name: "Carol",
role: "Student",
user_id: "147032",
},
];
for (var id in pageviews) {
var thisUser = pageviews[id].user_id;
console.log("To match - " + thisUser);
for (var id in enrollments) {
if (enrollments[id].user_id == thisUser) {
console.log("Returned - " + enrollments[id].nane);
}
}
}
So from what I understand, you are trying to get the names of enrollments that have matching user id to each pageview user_id. If that's what you are trying to achieve, then the below snippet should do it. Goodluck
var pageviews = [{
id: 1,
page: "Home",
user_id: "100032",
},
{
id: 2,
page: "Assignment 1",
user_id: "123032",
},
{
id: 3,
page: "Discussion 2",
user_id: "147032",
},
];
var enrollments = [{
id: 1,
name: "Amy",
role: "Student",
user_id: "100032",
},
{
id: 2,
name: "Bill",
role: "Teacher",
user_id: "123032",
},
{
id: 3,
name: "Carol",
role: "Student",
user_id: "147032",
},
];
// loop through the page views
pageviews.forEach(pageview => {
// then get the names of enrollements that matches the current pageview user_id
let enrollmentsNames = enrollments.filter(data => data.user_id === pageview.user_id).map(data => data.name);
// if the result is not empty, then log the names of enrollments that has matching user id with the current pageview user_id
if (enrollmentsNames.length) console.log(enrollmentsNames)
// if it's certain that a pageview won't have more than 1 enrollment then just go ahead and log the first element
if (enrollmentsNames.length) console.log(enrollmentsNames[0])
});
I think you're looking for something like this:
enrollments.forEach(enrollment => {
const pageviewinfo = pageviews.find(pageview => pageview.user_id === enrollment.user_id);
console.log(enrollment.name, pageviewinfo);
});
It loops through the enrollments and finds the pageview for a given user_id.
Good luck!
const pageviews = [{
id: 1,
page: "Home",
user_id: "100032",
},
{
id: 2,
page: "Assignment 1",
user_id: "123032",
},
{
id: 3,
page: "Discussion 2",
user_id: "147032",
},
];
const enrollments = [{
id: 1,
name: "Amy",
role: "Student",
user_id: "100032",
},
{
id: 2,
name: "Bill",
role: "Teacher",
user_id: "123032",
},
{
id: 3,
name: "Carol",
role: "Student",
user_id: "147032",
},
];
enrollments.forEach(enrollment => {
const pageviewinfo = pageviews.find(pageview => pageview.user_id === enrollment.user_id);
console.log(enrollment.name, pageviewinfo);
});

ES6 array of hashes return unique array of hashes [duplicate]

This question already has answers here:
Create array of unique objects by property
(17 answers)
Closed 3 years ago.
I have an object that looks like this:
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
]
I need an array of the unique user hashes like this:
[
{ id: 5564, name: 'john'},
{ id: 5560, name: 'jane'}
]
I'm able to retrieve all the users attributes from the posts array by doing:
const postUsers = posts.map(post => post.user)
which returns:
[
{ id: 5564, name: 'john'},
{ id: 5564, name: 'john'},
{ id: 5560, name: 'jane'}
]
where user john is listed twice
I've been able to get my desired result by doing:
const unique = {};
const uniqueUsers = [];
for(var i in postUsers){
if(typeof(unique[postUsers[i].id]) == "undefined"){
uniqueUsers.push(postUsers[i]);
}
unique[postUsers[i].id] = 0;
};
uniqueUsers
but there must be a cleaner way.
I've also been able to return the unique ids of all users by doing:
var ids = posts.map(post => post.user.id)
var uniqueIds = Array.from(new Set(ids)).sort();
which returns
[5564, 5560]
not sure if that helps. this article helped me a little https://medium.com/tomincode/removing-array-duplicates-in-es6-551721c7e53f
You could take a Map and get only the unique users.
const
posts = [{ id: 0, user: { id: 5564, name: 'john'} }, { id: 1, user: { id: 5564, name: 'john'} }, { id: 2, user: { id: 5560, name: 'jane'} }],
unique = Array.from(posts.reduce((m, { user }) => m.set(user.id, user), new Map).values());
console.log(unique);
If you don't mind using lodash you can do something like
const users = _map.(posts, 'user') // To get the list of users
_.uniqBy(users, 'id') // to get the uniq ones
Put the objects directly in uniqueUsers, then use Object.values() at the end to convert the object to an array.
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
];
let uniqueUsers = {};
posts.forEach(({user}) => uniqueUsers[user.id] = user);
uniqueUsers = Object.values(uniqueUsers);
console.log(uniqueUsers);
Use reduce to reduce the array by checking if the value is already in the array. If it is already in the array, return the current state of the array, otherwise add the item to the array.
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
]
const r = posts.map(i => i.user).reduce((acc, itm) => {
return !acc.find(i => i.id == itm.id) && acc.concat(itm) || acc
}, [])
console.log(r)

joining two streams of observables in RxJs according to specific conditions

I have two streams of objects, the accounts and balances.
I need to merge (join) the two streams according to the id and account_id
var accounts = Rx.Observable.from([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' },
]);
var balances = Rx.Observable.from([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 },
]);
What is expected:
var results = [
{ id: 1, name: 'account 1', balance: 100},
{ id: 2, name: 'account 2', balance: 200},
{ id: 3, name: 'account 3', balance: 300},
];
Is this feasible with RxJs ?
To be clear I know how to do this with plain js/lodash or something similar. In my case I am getting these streams from Angular Http Module, so I am asking If I could get benefit of RxJs in this case
Accoring to one of your comment, your example is to simulate a stream from an Angular Http call.
So instead of :
var accounts = Rx.Observable.from([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' },
]);
var balances = Rx.Observable.from([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 },
]);
I'd rather say that it is :
var accounts = Rx.Observable.of([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' },
]);
var balances = Rx.Observable.of([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 },
]);
Why : from will emit every item one by one, of will emit the entire array and I guess your http response is the whole array.
That said, what you probably want to achieve is :
const { Observable } = Rx;
// simulate HTTP requests
const accounts$ = Rx.Observable.of([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' }
]);
const balances$ = Rx.Observable.of([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 }
]);
// utils
const joinArrays = (accounts, balances) =>
accounts
.map(account => Object.assign({}, account, { balance: findBalanceByAccountId(balances, account.id).balance }));
const findBalanceByAccountId = (balances, id) =>
balances.find(balance => balance.account_id === id) || { balance: 0 };
const print = (obj) => JSON.stringify(obj, null, 2)
// use forkJoin to start both observables at the same time and not wait between every request
Observable
.forkJoin(accounts$, balances$)
.map(([accounts, balances]) => joinArrays(accounts, balances))
.do(rslt => console.log(print(rslt)))
.subscribe();
Output :
[
{
"id": 1,
"name": "account 1",
"balance": 100
},
{
"id": 2,
"name": "account 2",
"balance": 200
},
{
"id": 3,
"name": "account 3",
"balance": 300
}
]
Here's a working Plunkr : https://plnkr.co/edit/bc0YHrISu3FT45ftIFwz?p=preview
EDIT 1 :
Working on an array to compose your result is probably not the best idea for performance and instead of returning an array, maybe try to return an object which have as key, the ID of the account. This way you might simply remove the findBalanceByAccountId function and have a faster app (only modified code here) :
const balances$ = Rx.Observable.of({
1: { account_id: 1, balance: 100 },
2: { account_id: 2, balance: 200 },
3: { account_id: 3, balance: 300 }
});
// utils
const joinArrays = (accounts, balances) =>
accounts
.map(account => Object.assign(
{},
account,
{ balance: balances[account.id].balance }
));
If you have truly 2 observables that emit the results as Observable<{}> in random order, this is a way you can combine them. If the order is not random, or if they always come in 'pairs', more efficient way's exists to combine them.
import { from, merge } from 'rxjs';
import { map, scan, tap } from 'rxjs/operators';
const accounts = from([
{ id: 1, name: 'account 1' },
{ id: 2, name: 'account 2' },
{ id: 3, name: 'account 3' }
]);
const balances = from([
{ account_id: 1, balance: 100 },
{ account_id: 2, balance: 200 },
{ account_id: 3, balance: 300 }
]);
interface Outcome {
id: number;
name?: string;
balance?: number;
}
merge<Outcome>(
accounts,
balances.pipe(map(a => ({ id: a.account_id, balance: a.balance })))
)
.pipe(
scan<Outcome>((result: Outcome[], incomming) => {
const found = result.find(row => row.id === incomming.id);
if (found) {
Object.assign(found, incomming);
} else {
result.push(incomming);
}
return result;
}, []),
tap(r => console.log(r))
)
.subscribe();
Please note that the result is a hot observable. If you only want to emit a single result and complete when all results are in, replace the scan operator with the reduce operator.
The source is based on RXjs version 6. your imports might differ a bit on older versions.

Categories

Resources