I've been trying to group by multiple keys with lodash but it's not returning the correct results. The aim is to group by state and details but in this case it's joining/grouping docIds 333333 and 444444 which although have equal state (rejected), don't have the same id's in details (=> different people) so they don't share both conditions: state and id's in details.
It seems my current code does work with multiple criteria but once only one of the conditions exists it still performs the grouping, while I wanted to only group if both criteria were satisfied.
As for lodash approach It should show:
[
{
"docId": "222222,1111111",
"details": [
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
},
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Fellow Last Name"
}
],
"state": "accepted",
},
{
"docId": "333333",
"details": [
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Fellow Last Name"
}
],
"state": "rejected",
},
{
"docId": "444444",
"details": [
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
},
],
"state": "rejected",
}
]
I'm open to use plain js and have no problem in getting for example "docId": [{"333333"},{"444444"}] instead of comma separated values , or slightly different final result as long as the grouping in the end obeys to the same rules but I wasn't able to achieve the intended result either with plain js so I moved to lodash which seemed simpler.
In the end I will be needing some sorting to prioritize state, then groups with only one person in details and when one person, prioritize the ones with claimant but that's something that should be done afterwards, right?
Help would be much appreciated.
const data = [
{
docId: 222222,
state: "accepted",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
},
{
id: 10000,
type: "Fellow",
name: "Fellow First Name Fellow Last Name",
}
]
},
{
docId: 1111111,
state: "accepted",
details: [
{
id: 10000,
type: "Fellow",
name: "Fellow First Name Fellow Last Name",
},
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
}
]
},
{
docId: 333333,
state: "rejected",
details: [
{
id: 10000,
type: "Fellow",
name: "Fellow First Name Last Name",
}
]
},
{
docId: 444444,
state: "rejected",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
}
]
}
];
const grouped = _(data)
.groupBy(({details,state}) => `${details},${state}`)
.map((value, key) => ({
docId: _.map(value, 'docId').join(','),
details: value[0].details,
state: value[0].state,
document_file_name: value[0].document_file_name,
}))
.value()
console.log(grouped)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
First collect id by state and docId.
Second group collected data by state and sorted id and build new objects.
const
data = [{ docId: 222222, document_file_name: "4020653_FileName.pdf", document_updated_at: "2020-07-08T19:41:28.385Z", state: "accepted", details: [{ id: 20656, type: "Claimant", name: "First Name Last Name" }, { id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" }] }, { docId: 1111111, document_file_name: "4020600_FileName.pdf", document_updated_at: "2020-07-08T19:41:28.385Z", state: "accepted", details: [{ id: 10000, type: "Fellow", name: "Fellow First Name Fellow Last Name" }, { id: 20656, type: "Claimant", name: "First Name Last Name" }] }, { docId: 333333, document_file_name: "4020890_FileName.pdf", document_updated_at: "2020-07-08T19:41:28.385Z", state: "rejected", details: [{ id: 10000, type: "Fellow", name: "Fellow First Name Last Name" }] }, { docId: 444444, document_file_name: "4020672_FileName.pdf", document_updated_at: "2020-07-08T19:41:28.385Z", state: "rejected", details: [{ id: 20656, type: "Claimant", name: "First Name Last Name" }] }],
ids = {},
temp = data.reduce((r, { docId, state, details }) => {
const key = [state, docId].join('|');
details.forEach(o => {
ids[o.id] = o;
(r[key] ??= []).push(o.id);
});
return r;
}, {}),
grouped = Object.values(Object
.entries(temp)
.reduce((r, [k, v]) => {
const
[state, docId] = k.split('|'),
key = [state, v.sort().join('|')].join('#');
r[key] ??= { docId: '' , details: v.map(id => ids[id]), state };
r[key].docId += (r[key].docId && ', ') + docId;
return r;
}, {}));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I have a array of objects, and by using the foreach or map I want to create new array from its keys:
[{
"name": "Dentist Specialist",
"category": "Roles",
"path": "cde"
},
{
"name": "Root Canal Therapy",
"category": "Procedures",
"path": "abc"
},
{
"name": "Live Course",
"category": "Course Type",
"path": "mfg"
}]
From the above array I need a new ARRAY which will look like this:
[{
"Roles": "Dentist Specialist"
},
{
"Procedures": "Root Canal Therapy"
},
{
"Course Type": "Live Course"
}]
Just replace the 2nd key with the first key and remove the rest.
You can use map here to achieve the desired result.
arr.map(({ category, name }) => ({ [category]: name }));
or
arr.map((o) => ({ [o.category]: o.name }));
const arr = [
{
name: "Dentist Specialist",
category: "Roles",
path: "cde",
},
{
name: "Root Canal Therapy",
category: "Procedures",
path: "abc",
},
{
name: "Live Course",
category: "Course Type",
path: "mfg",
},
];
const result = arr.map((o) => ({ [o.category]: o.name }));
console.log(result);
How to return name and id property value of all arrays? The idea is to make a single map of all these arrays and return the id and name?
Something like this
filters.[key].map((option, index) => (
<ItemFilter key={index}>{option}</ItemFilter>
))
I have this array object
filters: {
"services": [
{
"id": "1b975589-7111-46a4-b433-d0e3c0d7c08c",
"name": "Bank"
},
{
"id": "91d4637e-a17f-4b31-8675-c041fe06e2ad",
"name": "Income"
}
],
"accountTypes": [
{
"id": "1f34205b-2e5a-430e-982c-5673cbdb3a68",
"name": "Digital Account"
}
],
"channels": [
{
"id": "875f8350-073e-4a20-be20-38482a86892b",
"name": "Chat"
}
]
}
You can use flatMap or flat to achieve the desired result.
Object.values(obj.filters).flatMap(v => v)
or
Object.values(obj.filters).flat()
const obj = {
filters: {
services: [
{
id: "1b975589-7111-46a4-b433-d0e3c0d7c08c",
name: "Bank",
},
{
id: "91d4637e-a17f-4b31-8675-c041fe06e2ad",
name: "Income",
},
],
accountTypes: [
{
id: "1f34205b-2e5a-430e-982c-5673cbdb3a68",
name: "Digital Account",
},
],
channels: [
{
id: "875f8350-073e-4a20-be20-38482a86892b",
name: "Chat",
},
],
},
};
const result = Object.values(obj.filters).flatMap(v => v);
console.log(result);
If option is referring to name in your example code it could look something like this:
Object.values(
{
filters: {
services: [
{
id: "1b975589-7111-46a4-b433-d0e3c0d7c08c",
name: "Bank",
},
{
id: "91d4637e-a17f-4b31-8675-c041fe06e2ad",
name: "Income",
},
],
accountTypes: [
{
id: "1f34205b-2e5a-430e-982c-5673cbdb3a68",
name: "Digital Account",
},
],
channels: [
{
id: "875f8350-073e-4a20-be20-38482a86892b",
name: "Chat",
},
],
},
}.filters
)
.flat()
.map(({ name, index }) => <ItemFilter key={index}>{name}</ItemFilter>);
I have a specific usecase where I want to combine all objects from an array into one new array. So I have a form in my website where users while booking are adding participants. They can add as many participants as they want. I save them in database as JSON and now I want to form a array of all participants so that I can show them all in the table.
So I first fetch all transactions from a specific listing which I get as an Array of objects and then I loop through them all and only get the transaction.attributes.protectedData.questions which holds the participants of each transaction.
So my transactions object looks like:
[
{
"type":"transaction",
"attributes":{
"createdAt":"2021-06-24T08:50:26.911Z",
"protectedData":{
"questions":[
[
{
"question":"name",
"answer":"Mario North"
},
{
"question":"email",
"answer":"mario#gmail.com"
}
]
],
"ticketType":{
"name":"Main entry",
"quantity":1
}
}
}
},
{
"type":"transaction",
"attributes":{
"createdAt":"2021-06-24T08:48:57.646Z",
"protectedData":{
"questions":[
[
{
"question":"name",
"answer":"John Adkins"
},
{
"question":"email",
"answer":"john#gmail.com"
}
],
[
{
"question":"name",
"answer":"Thomas Smith"
},
{
"question":"email",
"answer":"thomas#gmail.com"
}
]
],
"ticketType":{
"name":"General entry",
"quantity":2
}
}
}
}
]
So I need to loop through each transaction, then loop through questions and each new array in questions array is a new participant. In each participant I need to save the createdAt and ticketType values from transaction property.
So my final array/object needs to look like this:
[
{
"createdAt":"2021-06-24T08:50:26.911Z",
"ticketType":"Main entry",
"name":"Mario North",
"email":"mario#gmail.com"
},
{
"createdAt":"2021-06-24T08:48:57.646Z",
"ticketType":"General entry",
"name":"John Adkins",
"email":"john#gmail.com"
},
{
"createdAt":"2021-06-24T08:48:57.646Z",
"ticketType":"General entry",
"name":"Thomas Smith",
"email":"thomas#gmail.com"
}
]
So I can get the list of participants with createdAt and ticketType added to each of them. But I don't know how can I get my question/answer to appear as my wanted object I posted upper. This is what I have:
export const denormalisedParticipantList = transactions => {
let participants = [];
transactions.map(transaction => {
const createdAt = transaction.attributes.createdAt;
const questions = transaction.attributes.protectedData?.questions;
const ticketType = transaction.attributes.protectedData?.ticketType?.name;
return questions.map(q => {
// Form new participant object
const participant = {
createdAt,
ticketType,
...Object.fromEntries(q.map(({ question, answer }) => [question, answer])),
};
// Push new participant
participants.push(participant);
});
});
return participants;
};
I've been trying to figure it out since last night and I can't make it work. Can anyone please help me figure out how can I make a final array from my transactions object, I would be extremly thankful.
Destructuring can be a powerful way of keeping track of what you are accessing in a complex object. Here with flatMap() to return a single flattened array and Object.fromEntries() to map the questions array to individual objects.
const input = [{ "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:50:26.911Z", "protectedData": { "questions": [[{ "question": "name", "answer": "Mario North" }, { "question": "email", "answer": "mario#gmail.com" }]], "ticketType": { "name": "Main entry", "quantity": 1 } } } }, { "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:48:57.646Z", "protectedData": { "questions": [[{ "question": "name", "answer": "John Adkins" }, { "question": "email", "answer": "john#gmail.com" }], [{ "question": "name", "answer": "Thomas Smith" }, { "question": "email", "answer": "thomas#gmail.com" }]], "ticketType": { "name": "General entry", "quantity": 2 } } } }]
const result = input.flatMap((
{
attributes: {
createdAt,
protectedData: {
questions,
ticketType: { name: ticketType } }
}
}
) => (
questions.map(p => ({
createdAt,
ticketType,
...Object.fromEntries(p.map(({ question, answer }) => [question, answer]))
}))
));
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
var array = []
data.forEach((element) => {
var object = { created: null,ticketType: null,name: null,email: null }
object.created = element.attributes.createdAt;
object.ticketType = element.attributes.protectedData.ticketType.name;
var tmp_data = element.attributes.protectedData.questions;
tmp_data.forEach((tmp) => {
tmp.forEach((item) => {
if(item.question == "name"){
object.name = item.answer;
}else{
object.email = item.answer;
}
})
array.push(object);
})
})
try this :)
You can simply use reduce and map.
const data = [{ "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:50:26.911Z", "protectedData": { "questions": [[{ "question": "name", "answer": "Mario North" }, { "question": "email", "answer": "mario#gmail.com" }]], "ticketType": { "name": "Main entry", "quantity": 1 } } } }, { "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:48:57.646Z", "protectedData": { "questions": [[{ "question": "name", "answer": "John Adkins" }, { "question": "email", "answer": "john#gmail.com" }], [{ "question": "name", "answer": "Thomas Smith" }, { "question": "email", "answer": "thomas#gmail.com" },{ "question": "gender", "answer": "male" }]], "ticketType": { "name": "General entry", "quantity": 2 } } } }]
const output = data.reduce(
(a, b) => [
...a,
...b.attributes.protectedData.questions.map(e => ({
createdAt: b.attributes.createdAt,
ticketType: b.attributes.protectedData.ticketType.name,
...e.reduce((acc, cur) => ({ ...acc, [cur.question]: cur.answer }), {}),
})),
],
[]
);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am trying to merge two tree objects into one with the spread operator, but I am not getting the correct merged result.
How can I fully merge two tree objects with spread operator ?
const tree1 = [{
comments: [{
text: "This a comment for case law 84",
id: "84"
}, {
text: "This a comment for case law 89",
id: "89"
}],
children: [{
comments: [{
text: "This a comment for case law 70",
id: "70"
}],
children: [{
comments: [{
text: "This a comment for case law 83",
id: "83"
}]
}]
}]
}];
const tree2 = [{
comments: [{
text: "This a comment for case law 184",
id: "184"
}],
children: [{
comments: [{
text: "This a comment for case law 170",
id: "170"
}],
children: [{
comments: [{
text: "This a comment for case law 183",
id: "183"
}]
}]
}]
}];
const mergedTrees = [{ ...tree2, ...tree1 }];
console.log("mergedTrees", mergedTrees);
The problem is while merging the properties with the same key get overwritten. The rightmost property has the highest precedence.
What I need to get this kind of merge? :
{
"0": {
"comments": [
{
"text": "This a comment for case law 84",
"id": "84"
},
{
"text": "This a comment for case law 89",
"id": "89"
},
{
"text": "This a comment for case law 184",
"id": "184"
}
],
"children": [
{
"comments": [
{
"text": "This a comment for case law 70",
"id": "70"
},
{
"text": "This a comment for case law 170",
"id": "170"
}
],
"children": [
{
"comments": [
{
"text": "This a comment for case law 83",
"id": "83"
},
{
"text": "This a comment for case law 183",
"id": "183"
}
]
}
]
}
]
}
}
if it's not possible with the spread operator and there is another way to make it, please let me know.
adding a link for tries: https://stackblitz.com/edit/fffika?file=index.ts
You could merge the arrays index-wise and take the same approach for nested children.
const
merge = (a, b) => [a, b].reduce((r, array) => {
array.forEach(({ children, ...o }, i) => {
r[i] ??= { };
Object.entries(o).forEach(([k, v]) => (r[i][k] ??= []).push(...v));
if (children) r[i].children = merge(r[i].children || [], children);
});
return r;
}, []),
tree1 = [{ comments: [{ text: "This a comment for case law 84", id: "84" }], news: [{ text: "This news 1 ", id: "1" }], children: [{ comments: [{ text: "This a comment for case law 70", id: "70" }], news: [{ text: "This news 2 ", id: "2" }, { text: "This news 3 ", id: "3" }], children: [{ comments: [{ text: "This a comment for case law 83", id: "83" }], news: [{ text: "This news 4 ", id: "4" }] }] }] }],
tree2 = [{ comments: [{ text: "This a comment for case law 184", id: "184" }], news: [{ text: "This news 12 ", id: "12" }, { text: "This news 13 ", id: "13" }], children: [{ comments: [{ text: "This a comment for case law 170", id: "170" }], news: [{ text: "This news 22 ", id: "22" }, { text: "This news 33", id: "33" }], children: [{ comments: [{ text: "This a comment for case law 183", id: "183" }], news: [{ text: "This news 122 ", id: "122" }, { text: "This news 133 ", id: "133" }] }] }] }]
result = merge(tree1, tree2);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
With the below JSON content that is actually coming from an API but I'm using a json file for testing. I would like to combine the primary key and flatten the ItemList.
[{
"PrimaryKey": "123",
"ItemList": [
{
"SecondaryKey": "ABC",
"Name": "Item1",
"Description": "Sample item"
},
{
"SecondaryKey": "DEF",
"Name": "Item2",
"Description": "Another sample item"
}
],
"IgnoreThis": [
{
"SomeData": "Some Data"
}
]
}]
The output I would like is:
[{
"PrimaryKey": 123,
"SecondaryKey": "ABC",
"Name": "Item1",
"Description": "Sample Item"
},
{
"PrimaryKey": 123,
"SecondaryKey": "DEF",
"Name": "Item2",
"Description": "Another sample item"
}]
I've got the Item list being flattened by:
let items = [];
items.push(JSON.parse(fs.readFileSync('./items.json')));
let result = items.reduce((r, obj) => r.concat(obj.ItemList), []);
I've tried to use items.map to get the desired output nothing has worked, I don't think I understand how to chain .map and .reduce effectively as I get undefined as the result.
Any ideas how I can achieve this output?
You can do this by running map twice: get the PrimaryKey from the first map, then add it to all the objects inside the second map, then you flatten the array you got from the previous stage.
const data = [
{
PrimaryKey: "123",
ItemList: [
{
SecondaryKey: "ABC",
Name: "Item1",
Description: "Sample item",
},
{
SecondaryKey: "DEF",
Name: "Item2",
Description: "Another sample item",
},
],
IgnoreThis: [
{
SomeData: "Some Data",
},
],
},
{
PrimaryKey: "456",
ItemList: [
{
SecondaryKey: "ABC",
Name: "Item1",
Description: "Sample item",
},
{
SecondaryKey: "DEF",
Name: "Item2",
Description: "Another sample item",
},
],
IgnoreThis: [
{
SomeData: "Some Data",
},
],
},
];
const result = data.map(({ PrimaryKey, ItemList }) => ItemList.map(item => ({
PrimaryKey,
...item,
}))).flat();
console.log(result);