Map a new key-value pair into an array of objects - javascript

I would like to add a new key-value pair to all objects within my data. The structure looks like this:
userData:
[
{
"id": 1,
"name": "John Doe",
"email": "xyz.com"
},
{
"id": 2,
"name": "Jane Doe",
"email": "zzz.com"
},
{
"id": 3,
"name": "Anne Doe",
"email": "yyy.com"
}
]
As a new key-value pair, I would like to add "logged-in": true/false.
To get this data, I use another service. And then I map the true/false values into a variable.
const activeUser = await this.userService.getUserProfile().toPromise();
this.currentUser = activeUser.id;
this.loggedInUser = this.getAccountDetails.map(user => ({
self: this.currentUser === user.id
})
)
Then, I would like to push these key-value pairs into userData.
loggedInUser: { self: boolean }[];
addUserStatus() {
this.userData.map((data, i) => ({ ...data,
"logged-in": this.loggedInUser[i].self
}))
}
What I would like to achieve:
userData:
[
{
"id": 1,
"name": "John Doe",
"email": "xyz.com",
"logged-in": true
},
{
"id": 2,
"name": "Jane Doe",
"email": "zzz.com",
"logged-in": false
},
{
"id": 3,
"name": "Anne Doe",
"email": "yyy.com",
"logged-in": false
}
]
What did I do wrong here?

map returns new data, so your function should look something like this
loggedInUser: { self: boolean }[];
addUserStatus() {
const temp = this.userData.map((data, i) => ({ ...data,
"logged-in": this.loggedInUser[i].self
}))
this.userData = temp
}
If you want to modify this.userData directly, you can use other methods like forEach
addUserStatus() {
this.userData.forEach((data, i) => {
data["logged-in"] = this.loggedInUser[i].self;
};
}

You can simply change the map in addUserStatus to forEach, where you can mutate the entries and add the logged-in property:
addUserStatus() {
this.userData.forEach((data, i) => {
data["logged-in"] = this.loggedInUser[i].self;
};
}

Related

How to combine and nest related JSON objects?

I have two json files that I would like to combine into a single json object that can be read on my front end.
fragments.json
[
{
"id": 2,
"title": "John Smith is nice",
"reports": "1,2",
"entities": 1,
}
]
entities.json
[
{
"id": 1,
"fragments": 2,
"name": "John SMITH",
"dateOfBirth": "4/24/1967",
}
]
Desired Result.json
I want to show all the entities that are connected to any given fragment.
[
{
"id":2,
"title":"John Smith is nice",
"reports":"1,2",
"entities":{
"id":1,
"fragments":2,
"name":"John SMITH",
"dateOfBirth":"4/24/1967"
}
}
]
Here's my code so far:
router.get('/sprint-3/:prototype/report/:reportId', function (req, res) {
const slug = +req.params.reportId
const report = reports.find(({ id }) => id === slug);
const reportFragments = fragments.filter(({ reports }) => reports.includes(report.id) );
reportFragments.forEach(fragment => {
const reportEntities = entities.filter(({ fragments }) => fragments === fragment.id );
reportFragments.push(reportEntities);
console.log('New', reportFragments)
});
res.render("sprint-3/prototype-1/report", { report: report, fragments: reportFragments });
});
I've been looking at .push as a way of doing this, but currently it appends the entities to the end of the reportFragments rather than nesting inside each of them.
You can use reduce like so
const reportFragments = [{
"id": 2,
"title": "John Smith is nice",
"reports": "1,2",
"entities": 1,
}]
const entities = [{
"id": 1,
"fragments": 2,
"name": "John SMITH",
"dateOfBirth": "4/24/1967",
}]
const merged = reportFragments.reduce((acc, curr) => {
const match = entities.filter(ent => ent.fragments === curr.id);
return [...acc, ({
id: curr.id,
title: curr.title,
reports: curr.reports,
...{
entities: match
}
})]
}, [])
console.log(merged)

Filter an nested Object with filter and map with JavaScript

I know that this is close to a duplicate but I can't get the code to work. I have an object that I need to filter and I'm currently trying to emulate the accepted as an answer the code at Javascript filtering nested arrays
My data object is:
[{
"project_num": "5R01DA012513-23",
"principal_investigators": [{
"profile_id": 2076451,
"full_name": "PK",
"title": ""
}]
},
{
"project_num": "5R01DK118529-03",
"principal_investigators": [{
"profile_id": 8590844,
"full_name": "HW",
"title": "PROFESSOR, SCIENTIFIC DIRECTOR"
}]
},
{
"project_num": "3R01AA025365-05S1",
"principal_investigators": [{
"profile_id": 8730036,
"full_name": "JJ",
"title": "ASSOCIATE PROFESSOR OF PSYCHIATRY"
}]
},
{
"project_num": "1R01HL163963-01",
"principal_investigators": [{
"profile_id": 2084037,
"full_name": "KH",
"title": "ASSOCIATE PROFESSOR"
},
{
"profile_id": 11309656,
"full_name": "AM",
"title": "RESEARCH ASSISTANT PROFESSOR"
}
]
},
{
"project_num": "5R25HL092611-15",
"principal_investigators": [{
"profile_id": 1886512,
"full_name": "CW",
"title": "P"
}]
}
]
and my JavaScript code is:
let payLoad = 1886512
const result = this.reporterData.map(t => {
const principal_investigators = t.principal_investigators.filter(d =>
d.profile_id === payLoad);
return { ...t,
principal_investigators
};
})
I need to pass in a profile_id as a payload and return the objects that will fill a data table.
The data can be 1000's of items and the principla_investigators can be multiple entries. When I use the code that I have it return all of the objects. Can someone point out my error? Thanks
You can try doing like this:
const result = this.reporterData.filter((t) => {
const principal_investigators = t.principal_investigators.filter((d) => d.profile_id === payLoad)
return (principal_investigators.length > 0)
})
I understand that you want an array with all the investigators matching that ID, right?
Try this:
const result = this.reporterData.reduce((previous, current) => {
if (current.principal_investigators) {
current.principal_investigators.forEach(pi => {
if (pi.profile_id === payLoad) {
previous.push(current)
}
});
}
return previous
}, [])
You can also do for loops with the same result:
const result = [];
for (project of this.reporterData) {
if (project.principal_investigators) {
for (pi of project.principal_investigators) {
if (pi.profile_id == payLoad) {
result.push(pi);
}
}
}
}

Create a new object in Angular 11 app based on values in another array of objects

I am having an Angular 11 app in which I have an array of objects as shown below.
details = [
{
"name": "firstName",
"content": "Tom"
},
{
"name": "lastName",
"content": "Smith"
},
{
"name": "email",
"content": "tomsmith#test.com"
}
]
I want to create an object from above array as shown below.
output = {
firstName: {value: "Tom"},
lastName: {value: "Smith"},
email: {value: "tomsmith#test.com"}
}
For simplicity I have only shown 3 objects in the details array but there can be any number of them. So I want the conversion to happen irrespective of the number of objects in the details array. How can I create the above output object? Please help me out.
you could do with Array#reduce.
const details = [ { "name": "firstName", "content": "Tom" }, { "name": "lastName", "content": "Smith" }, { "name": "email", "content": "tomsmith#test.com" } ];
const res = details.reduce(
(acc, {name, content: value}) => (acc[name] = {value}, acc), {}
);
console.log(res)
Not that I'm against to the other answers proposed. As an alternative you can also do it with the help of a "for-of" loop and applying destructured assignment.
const details = [ { "name": "firstName", "content": "Tom" }, { "name": "lastName", "content": "Smith" }, { "name": "email", "content": "tomsmith#test.com" } ];
let result = {}
for ({ name: n, content: value } of details) { result[n] = { value: value }; }
console.log(result)
MDN Reference - Deconstructuring Assignment
Map the array to an array of [name, { value }] pairs, and convert to an object using Object.fromEntries().
With Typescript you'll need to set the target as ES2019 at least in your TS config, and it doesn't require any type definition (TS Playground).
const details = [{"name":"firstName","content":"Tom"},{"name":"lastName","content":"Smith"},{"name":"email","content":"tomsmith#test.com"}]
const result = Object.fromEntries(
details.map(({ name, content: value }) => [name, { value }])
)
console.log(result)

How to parse FractalTransformer with normalizr

I'm trying to use paularmstrong/normalizr on JSON that comes from FractalTransformer and whose nested childs have "data" attribute. Example of JSON:
{
"data": {
"object": "Offer",
"id": "5g6aqocew4qjzl40",
"real_id": 26,
"name": "Random Name",
"created_at": {
"date": "2019-06-18 11:13:08.000000",
"timezone_type": 3,
"timezone": "UTC"
},
"readable_created_at": "1 year ago",
"site": {
"data": {
"object": "Site",
"id": "65zody8vj29vlegd",
"name": "Test Site",
"real_id": 1
}
},
"countries": {
"data": [
{
"object": "Country",
"code": "US",
"name": "United States"
},
{
"object": "Country",
"code": "DE",
"name": "Germany"
}
]
}
},
"meta": {
"include": [
"site",
"countries"
],
"custom": []
}
}
Schemas I use:
export const offerSchema = new schema.Entity('offers')
export const siteSchema = new schema.Entity('sites', {}, {
processStrategy: (value) => {
return { ...value.data }
},
idAttribute: (value) => {
return value.data.id
},
})
export const countrySchema = new schema.Entity('countries')
offerSchema.define({
site: siteSchema,
countries: [countrySchema],
})
Now the issue is that I remove 'data' from the site since it's just one object successfully, but I can't do it in the country case. Whatever I tried with custom processStrategy fails, as country is object that has data which is array (I assume this is where the issue is, going from Entity to Array). And in idAttribute function I always get complete array so can't determine the ID of single entry. So the end result is that the ID of countries is undefined. Any ides?
I actually managed with another approach. I added processStrategy on the parent, 'Offer' in this case, so all 'data' parts get stripped before they reach other child schemas.
const normalizrStripDataOptions = {
processStrategy: (value) => {
const ret = { ...value }
Object.keys(ret).forEach((key) => {
if (ret[key] !== null) {
if (ret[key].data && Array.isArray(ret[key].data)) {
ret[key] = [...ret[key].data]
}
if (ret[key].data && typeof ret[key].data === 'object') {
ret[key] = { ...ret[key].data }
}
}
})
return ret
},
}
export const offerSchema = new schema.Entity('offers', {}, normalizrStripDataOptions)
export const siteSchema = new schema.Entity('sites')
export const countrySchema = new schema.Entity('countries')
offerSchema.define({
site: siteSchema,
countries: [countrySchema],
})

Testing values of array objects

If i have an array like:
[
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "rr#co.com"
}
]
But it's not always being returned in that order - how can i check if ryan, for example, exists somewhere in one of these objects?
If you are already using lodash (or want to) then I would use its find:
_.find(array, { user: "ryan" })
Or with a few more characters you can do it without lodash:
array.find(elem => elem.user === "ryan")
Both return undefined if a matching element is not found.
Function return true if array contains ryan.
var input = [
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "rr#co.com"
}
]
var output = input.some(function(eachRow){
return eachRow.user === 'ryan';
});
console.log(output);
My method to solve that is to extract the targeted fields into arrays then check the value.
const chai = require('chai');
const expect = chai.expect;
describe('unit test', function() {
it('runs test', function() {
const users = [
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "ryan#co.com"
}
];
const names = extractField(users, 'user'); // ['tom', 'james', 'ryan']
expect(names).to.include('ryan');
});
function extractField(users, fieldName) {
return users.map(user => user[fieldName]);
}
});
I'm using chai for assertion. In case you want to check in other fields, we just use the extract methods.
const emails = extractField(users, 'email');
expect(emails).to.include('ryan');
Hope it helps

Categories

Resources