I have a json where I need to reduce the items when they are of a type (isSender).
I need to reduce them when they are occurring consecutively.
The data can change.
The data looks like this:
"messages": [
{ "content": ["Foo"], "isSender": true },
{ "content": ["Bar"], "isSender": true },
{ "content": ["Lorem"], "isSender": true },
{ "content": ["Ipsum"], "isSender": true },
{ "content": ["Dolor"], "isSender": false },
{ "content": ["Sit Amet"], "isSender": false },
{ "content": ["No"], "isSender": true }
]
I need the content to be an array of messages when the consecutive isSender key is the same. The output should look like this:
"messages": [
{
"content": ["Foo", "Bar", "Lorem", "Ipsum"],
"isSender": true
},
{ "content": ["Dolor", "Sit amet"], "isSender": false },
{ "content": ["No"], "isSender": true }
]
So far I have tried looping through the message array and checking if next messages have the same isSender key. However this does not work for more than 2 messages.
let deleteIndex = [];
for(let i = 0 ; i < messages.length - 1; i++) {
const currMs = messages[i];
const nextMs = messages[i + 1];
if (nextMs.isSender == currMs.isSender) {
currMs.content.push(nextMs)
deleteIndex.push(i + 1) // saving index to be deleted once for loop is done
}
}
Can someone give me a clue on how to work around this?
Thanks in advance.
Use reduce(), on each iteration, we check if the last element in the result array has the same isSender value as the current object we're dealing with.
if (p.length && p.at(-1).isSender === c.isSender) {
So, if we already have something in the final array (p.length) AND the last isSender (p.at(-1).isSender) has the same value as the current isSender (c.isSender), append to that content list
Otherwise, add the entry, which is just the current object itself (return [ ...p, c ])
const data = [
{ "content": ["Foo"], "isSender": true },
{ "content": ["Bar"], "isSender": true },
{ "content": ["Lorem"], "isSender": true },
{ "content": ["Ipsum"], "isSender": true },
{ "content": ["Dolor"], "isSender": false },
{ "content": ["Sit Amet"], "isSender": false },
{ "content": ["No"], "isSender": true }
];
const res = data.reduce((p, c) => {
if (p.length && p.at(-1).isSender === c.isSender) {
p.at(-1).content.push(...c.content);
return p;
}
return [ ...p, c ];
}, [])
console.log(res);
Should you not like the push way, we can use Object.assign to alter the index itself:
let i = p.length - 1;
return Object.assign([...p], { [i]: { ...p[i], content: [ ...p[i].content, ...c.content ]}});
const data = [
{ "content": ["Foo"], "isSender": true },
{ "content": ["Bar"], "isSender": true },
{ "content": ["Lorem"], "isSender": true },
{ "content": ["Ipsum"], "isSender": true },
{ "content": ["Dolor"], "isSender": false },
{ "content": ["Sit Amet"], "isSender": false },
{ "content": ["No"], "isSender": true }
];
const res = data.reduce((p, c) => {
if (p.length && p.at(-1).isSender === c.isSender) {
let i = p.length - 1;
return Object.assign([...p], { [i]: { ...p[i], content: [ ...p[i].content, ...c.content ]}});
}
return [ ...p, c ];
}, [])
console.log(res);
Javascript spread on array index to 'push' new item to nested array
[
{
"content": ["Foo", "Bar", "Lorem", "Ipsum"],
"isSender": true
},
{
"content": ["Dolor", "Sit Amet"],
"isSender": false
},
{
"content": ["No"],
"isSender": true
}
]
you can try this
var res = {
messages: [
{ content: [], isSender: true },
{ content: [], isSender: false },
{ content: [], isSender: false }
]
};
messages.messages.forEach((item) => {
if (item.content[0] == "No") {
res.messages[2].content = ["No"];
res.messages[2].isSender = item.isSender;
}
else {
if (item.isSender)
res.messages[0].content.push(...item.content);
else res.messages[1].content.push(...item.content);
}
});
console.log(JSON.stringify(res, null, 4));
json output
{
"messages": [
{
"content": [
"Foo",
"Bar",
"Lorem",
"Ipsum"
],
"isSender": true
},
{
"content": [
"Dolor",
"Sit Amet"
],
"isSender": false
},
{
"content": [
"No"
],
"isSender": true
}
]
}
Related
I want to delete all occurances of keynames like etag,formattedType and metadata in the object using dynamic iteration of whole object
var myjson {
"etag": "%EiIBAgMFBgcICQoLDA0ODxATFBUWGSEiIyQlJicuNTc9Pj9AGgECIdgxQTUREdTBneFMzZz0=",
"names": [{
"unstructuredName": "Natalie Victor",
"displayNameLastFirst": "Victor, Natalie",
"familyName": "Victor",
"displayName": "Natalie Victor",
"givenName": "Natalie",
"metadata": {
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
},
"primary": true
}
}],
"photos": [{
"metadata": {
"primary": true,
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
},
"url": "https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAdAA/V8BNOaftJmdYPfvspCwKr2nuTmSEuXTHowCLcDEAEiGQoBThD___________8BGKjbxPr______wE/s100/photo.jpg",
"default": true
}],
"memberships": [{
"metadata": {
"source": {
"type": "CONTACT",
"id": "c8de0718a7c3458"
}
},
"contactGroupMembership": {
"contactGroupId": "6a68e3a408126601",
"contactGroupResourceName": "contactGroups/6a68e3a408126601"
}
}, {
"contactGroupMembership": {
"contactGroupId": "myContacts",
"contactGroupResourceName": "contactGroups/myContacts"
},
"metadata": {
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
}
}],
"phoneNumbers": [{
"value": "6767674765",
"formattedType": "Home",
"canonicalForm": "+916767674765",
"metadata": {
"primary": true,
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
},
"type": "home"
}],
"emailAddresses": [{
"type": "home",
"formattedType": "Home",
"value": "nati_a_j#hotmail.com",
"metadata": {
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
},
"primary": true
}
}],
"biographies": [{
"contentType": "TEXT_PLAIN",
"value": "Email: ssww#gmail.com\nName.Last: Victor\nName.First: Natalie\nPhone: 6767674765",
"metadata": {
"primary": true,
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
}
}],
"resourceName": "people/c904625878430659672"
}
I only know to use delete key by names such as
delete myjson.etag
delete myjson.names[0].metadata
How do I iterate the complete json since some of the json has arrays and nested structures which are not known in advance.
Hence a remove_keys(myjson, ["etag","memberships","formattedType","metadata"]) should render a result
var myjson {
"names": [{
"unstructuredName": "Natalie Victor",
"displayNameLastFirst": "Victor, Natalie",
"familyName": "Victor",
"displayName": "Natalie Victor",
"givenName": "Natalie",
}],
"photos": [{
"url": "https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAdAA/V8BNOaftJmdYPfvspCwKr2nuTmSEuXTHowCLcDEAEiGQoBThD___________8BGKjbxPr______wE/s100/photo.jpg",
"default": true
}],
"phoneNumbers": [{
"value": "6767674765",
"canonicalForm": "+916767674765",
"type": "home"
}],
"emailAddresses": [{
"type": "home",
"value": "nati_a_j#hotmail.com",
}],
"biographies": [{
"contentType": "TEXT_PLAIN",
"value": "Email: ssww#gmail.com\nName.Last: Victor\nName.First: Natalie\nPhone: 6767674765",
}],
"resourceName": "people/c904625878430659672"
}
You need a recursive function for this task:
function filter(obj: any, list: string[]) {
if (obj && typeof obj === 'object') {
for (let item in obj) {
if (list.includes(item)) {
delete obj[item];
} else {
if (Array.isArray(obj[item])) {
for (let el of obj[item]) {
filter(el, list);
}
} else {
filter(obj[item], list);
}
}
}
}
return obj;
}
// example usage:
let a = {b: 5, c: 6, d: { a: 1, b: 2}}
filter(a, ['b']);
console.log(a);
Conversely, it may be faster in some interpreters to rebuild the object, rather than delete keys.
function removeKeys(obj, keys) {
if (Array.isArray(obj))
return obj.map(v => removeKeys(v, keys))
else if (typeof obj == "object" && obj != null) {
const _obj = {}
Object.keys(obj).forEach(k => {
if(!keys.includes(k)) _obj[k] = removeKeys(obj[k], keys)
})
return _obj
}
else
return obj
}
console.log(removeKeys(myjson, ["etag","memberships","formattedType","metadata"]))
this recursive function will solve your problem
var myjson = {
"etag":"%EiIBAgMFBgcICQoLDA0ODxATFBUWGSEiIyQlJicuNTc9Pj9AGgECIdgxQTUREdTBneFMzZz0=",
"names":[
{
"unstructuredName":"Natalie Victor",
"displayNameLastFirst":"Victor, Natalie",
"familyName":"Victor",
"displayName":"Natalie Victor",
"givenName":"Natalie",
"metadata":{
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
},
"primary":true
}
}
],
"photos":[
{
"metadata":{
"primary":true,
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
},
"url":"https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAdAA/V8BNOaftJmdYPfvspCwKr2nuTmSEuXTHowCLcDEAEiGQoBThD___________8BGKjbxPr______wE/s100/photo.jpg",
"default":true
}
],
"memberships":[
{
"metadata":{
"source":{
"type":"CONTACT",
"id":"c8de0718a7c3458"
}
},
"contactGroupMembership":{
"contactGroupId":"6a68e3a408126601",
"contactGroupResourceName":"contactGroups/6a68e3a408126601"
}
},
{
"contactGroupMembership":{
"contactGroupId":"myContacts",
"contactGroupResourceName":"contactGroups/myContacts"
},
"metadata":{
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
}
}
],
"phoneNumbers":[
{
"value":"6767674765",
"formattedType":"Home",
"canonicalForm":"+916767674765",
"metadata":{
"primary":true,
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
},
"type":"home"
}
],
"emailAddresses":[
{
"type":"home",
"formattedType":"Home",
"value":"nati_a_j#hotmail.com",
"metadata":{
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
},
"primary":true
}
}
],
"biographies":[
{
"contentType":"TEXT_PLAIN",
"value":"Email: ssww#gmail.com\nName.Last: Victor\nName.First: Natalie\nPhone: 6767674765",
"metadata":{
"primary":true,
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
}
}
],
"resourceName":"people/c904625878430659672"
}
function removeKeys(obj,keys){
if(Array.isArray(obj)){
obj.forEach(innerObj=>{
removeKeys(innerObj,keys)
})
}else{
keys.forEach(k=>{
delete obj[k];
})
Object.keys(obj).forEach(key=>{
if(typeof obj[key]=='object'){
removeKeys(obj[key],keys)
}
})
}
}
removeKeys(myjson, ["etag","memberships","formattedType","metadata"])
console.log(myjson);
I have a JSON array as follows :
[{
"name": "ABC",
"default": false,
"details": [
{
"detail1": "value1"
},
{
"detail2": "value2"
}
]
},
{
"name": "PQR",
"default": false,
"details": [
{
"detail3": "value3"
},
{
"detail4": "value4"
}
]
},
{
"name": "XYZ",
"default": true,
"details": [
{
"detail5": "value5"
},
{
"detail6": "value6"
}
]
}]
Now if the default value is true , I want it to be the first element of the array and rest of the elements should be sorted alphabetically based on the name . Only one of the element will have default as true or all the elements will have default as false.
The expected JSON after sorting should be :
[{
"name": "XYZ",
"default": true,
"details": [
{
"detail5": "value5"
},
{
"detail6": "value6"
}
]
},
{
"name": "ABC",
"default": false,
"details": [
{
"detail1": "value1"
},
{
"detail2": "value2"
}
]
},
{
"name": "PQR",
"default": false,
"details": [
{
"detail3": "value3"
},
{
"detail4": "value4"
}
]
}]
I have tried this code for sorting the JSON array :
jsonArray.sort( function( a, b ) {
a = a.name.toLowerCase();
b = b.name.toLowerCase();
return a < b ? -1 : a > b ? 1 : 0;
});
But I am not able to figure out how to check for the default value and sort accordingly. How do I achieve the expected result?
You're on the right way. Just modify the function to include the check for default:
jsonArray.sort( function( a, b ) {
const name1 = a.name.toLowerCase();
const name2 = b.name.toLowerCase();
return (b.default - a.default) || ((name1 > name2) - (name2 > name1))
});
I've got the quick code for string comparison from here: https://stackoverflow.com/a/17765169/2244262
I filtering group of object like this:
[
{
"Username":"00d9a7f4-0f0b-448b-91fc-fa5aef314d06",
"Attributes":[
{
"Name":"custom:organization",
"Value":"zxc"
},
{
"Name":"sub",
"Value":"00d9a7f4-0f0b-448b-91fc-fa5aef314d06"
},
{
"Name":"email_verified",
"Value":"false"
},
{
"Name":"email",
"Value":"zigor#freeallapp.com"
}
],
"UserCreateDate":"2021-02-04T17:59:28.212Z",
"UserLastModifiedDate":"2021-02-04T17:59:28.212Z",
"Enabled":true,
"UserStatus":"UNCONFIRMED"
},
{
"Username":"07c16a30-b994-4267-9794-6fb20739abeb",
"Attributes":[
{
"Name":"custom:organization",
"Value":"asd"
},
{
"Name":"sub",
"Value":"07c16a30-b994-4267-9794-6fb20739abeb"
},
{
"Name":"email_verified",
"Value":"false"
},
{
"Name":"email",
"Value":"2marwan.khatar.39#dankq.com"
}
],
"UserCreateDate":"2021-02-04T17:56:13.787Z",
"UserLastModifiedDate":"2021-02-04T17:56:13.787Z",
"Enabled":true,
"UserStatus":"UNCONFIRMED"
},
Following is filtering fine
let filterarry;
filterarry = jsonObject.filter(Attributes => {
return Attributes.Enabled == true && Attributes.UserStatus == 'UNCONFIRMED';
});
console.log(filterarry);
I am trying to filter by Attributes having:
Attributes that have custom:organization and with value zxc
how can I do that ??
"Attributes":[
{
"Name":"custom:organization",
"Value":"zxc"
},
I tried few methods but i am getting empty array in output
Thanks
You can do this:
let output = jsonObject.filter(entry => {
// filter the internal array and check
if (entry.Attributes.filter(attr => attr.Name === 'custom:organization' && attr.Value === 'zxc').length !== 0) {
return true;
}
return false;
});
See also: https://stackoverflow.com/a/8217584/14133230
To filter jsonObject.Attributes you need to recreate and the variable
let filterarry = jsonObject.filter(item => {
item.Attributes = item.Attributes.filter(attr => {
return attr.Name == "custom:organization" && attr.Value == "zxc"
})
// return true => to remove only value of jsonObject.Attributes but not the parent
return item.Attributes.length;
});
results
[
{
"Username": "00d9a7f4-0f0b-448b-91fc-fa5aef314d06",
"Attributes": [
{
"Name": "custom:organization",
"Value": "zxc"
}
],
"UserCreateDate": "2021-02-04T17:59:28.212Z",
"UserLastModifiedDate": "2021-02-04T17:59:28.212Z",
"Enabled": true,
"UserStatus": "UNCONFIRMED"
}
]
you can try this
const oObjects = [{
"Username": "00d9a7f4-0f0b-448b-91fc-fa5aef314d06",
"Attributes": [{
"Name": "custom:organization",
"Value": "zxc"
},
{
"Name": "sub",
"Value": "00d9a7f4-0f0b-448b-91fc-fa5aef314d06"
},
{
"Name": "email_verified",
"Value": "false"
},
{
"Name": "email",
"Value": "zigor#freeallapp.com"
}
],
"UserCreateDate": "2021-02-04T17:59:28.212Z",
"UserLastModifiedDate": "2021-02-04T17:59:28.212Z",
"Enabled": true,
"UserStatus": "UNCONFIRMED"
},
{
"Username": "07c16a30-b994-4267-9794-6fb20739abeb",
"Attributes": [{
"Name": "custom:organization",
"Value": "asd"
},
{
"Name": "sub",
"Value": "07c16a30-b994-4267-9794-6fb20739abeb"
},
{
"Name": "email_verified",
"Value": "false"
},
{
"Name": "email",
"Value": "2marwan.khatar.39#dankq.com"
}
],
"UserCreateDate": "2021-02-04T17:56:13.787Z",
"UserLastModifiedDate": "2021-02-04T17:56:13.787Z",
"Enabled": true,
"UserStatus": "UNCONFIRMED"
},
];
const filterarry = oObjects.filter(attr => {
return attr.Enabled &&
attr.UserStatus === 'UNCONFIRMED' &&
attr.Attributes.some(p => p.Name === "custom:organization" && p.Value === "zxc");
});
console.log(filterarry);
I have following data and unable to filter
{
"data": {
"Viewer": {
"CampaignGrids": {
"edges": [
{
"node": {
"Name": "mega campaign",
"Start_Date": "08/31/2020",
"End_Date": "09/15/2020",
"Promoted_Titles": [
{
"Primary_ISBN": "4314323211",
"Book": null
},
{
"Primary_ISBN": "94232344",
"Book": null
},
{
"Primary_ISBN": "221235345",
"Book": null
}
]
}
},
{
"node": {
"Name": "InActiveBook Campaign",
"Start_Date": "08/14/2019",
"End_Date": "08/14/2019",
"Promoted_Titles": [
{
"Primary_ISBN": "9781504011815",
"Book": {
"Primary_ISBN": "9781504011815",
"Active": true
}
},
{
"Primary_ISBN": "9780795336874",
"Book": {
"Primary_ISBN": "9780795336874",
"Active": true
}
},
{
"Primary_ISBN": "9781453244517",
"Book": {
"Primary_ISBN": "9781453244517",
"Active": true
}
},
{
"Primary_ISBN": "9781781892527",
"Book": {
"Primary_ISBN": "9781781892527",
"Active": false
}
}
]
}
}
]
}
}
}
}
I need to filter all the campaigns which contain Active : False book
So based on above data, i need to get back following
{"node": {
"Name": "InActiveBook Campaign",
"Start_Date": "08/14/2019",
"End_Date": "08/14/2019",
"Promoted_Titles": [
{
"Primary_ISBN": "9781504011815",
"Book": {
"Primary_ISBN": "9781504011815",
"Active": true
}
},
{
"Primary_ISBN": "9780795336874",
"Book": {
"Primary_ISBN": "9780795336874",
"Active": true
}
},
{
"Primary_ISBN": "9781453244517",
"Book": {
"Primary_ISBN": "9781453244517",
"Active": true
}
},
{
"Primary_ISBN": "9781781892527",
"Book": {
"Primary_ISBN": "9781781892527",
"Active": false
}
}
]
}
}
Currently i am using lodash library filter options. I tried following but it returns me both the data instead of just one
let flaged = _.filter(campaigns, function(item) {
return _.filter(item.Promoted_Titles, function(o) {
return o.Book.Active = false;
})
});
console.log('flagged campaign ', JSON.stringify(flaged) , '\n');
I also tried following
let flaged = filter(campaigns, function(el) {
el.Promoted_Titles = filter(el.Promoted_Titles, function(item) {
console.log('item is ', item);
return 'Book.Active' == false
})
return el;
})
But in both scenario, i get both item instead of just one. Thanks in advance
You can do this with Lodash by defining the structure of a match in a callback object like so:
let d = {"data":{"Viewer":{"CampaignGrids":{"edges":[{"node":{"Name":"mega campaign","Start_Date":"08/31/2020","End_Date":"09/15/2020","Promoted_Titles":[{"Primary_ISBN":"4314323211","Book":null},{"Primary_ISBN":"94232344","Book":null},{"Primary_ISBN":"221235345","Book":null}]}},{"node":{"Name":"InActiveBook Campaign","Start_Date":"08/14/2019","End_Date":"08/14/2019","Promoted_Titles":[{"Primary_ISBN":"9781504011815","Book":{"Primary_ISBN":"9781504011815","Active":true}},{"Primary_ISBN":"9780795336874","Book":{"Primary_ISBN":"9780795336874","Active":true}},{"Primary_ISBN":"9781453244517","Book":{"Primary_ISBN":"9781453244517","Active":true}},{"Primary_ISBN":"9781781892527","Book":{"Primary_ISBN":"9781781892527","Active":false}}]}}]}}}}
let e = d.data.Viewer.CampaignGrids.edges;
let a = _.filter(e, { node: { Promoted_Titles: [{ Book: { Active: false } }] } });
console.log(a);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
you have an object key called edges which is your array of nodes.
const results = edges.filter( edge => {
return edge.node.Promoted_Titles.filter( promotedTitles => promotedTitles.Book.Active === false).length > 0)
});
This will return a list of edges which contain at least 1 inactive book.
Edit: I just swapped it around to show a list of edges / campaigns where there is at least 1 inactive book per your comments.
I have the following input object
{
"id": 1,
"isLeaf": false,
"name": "New rule",
"pid": 0,
"dragDisabled": true,
"children": [
{
"id": "new1",
"value": "data1",
"then": false,
"type": "set",
"forEach": false,
"pid": 1
},
{
"id": "new2",
"value": "data2",
"then": true,
"type": "if",
"forEach": false,
"pid": 1,
"children": [
{
"id": "new3",
"type": "Then",
"enableElse": true,
"pid": "new2",
"children": [
{
"id": "new5",
"value": "data3",
"then": false,
"type": "fuzzy_search",
"forEach": false,
"pid": "new3"
}
]
},
{
"id": "new4",
"type": "Else",
"enableElse": true,
"pid": "new2",
"children": [
{
"id": "new6",
"value": "data4",
"then": false,
"type": "return",
"forEach": false,
"pid": "new4"
}
]
}
]
}
]
}
I need to convert it into the following json
[
{
"id": "new1",
"condition": "data1"
},
{
"id": "new2",
"condition": "data2",
"then": [{
"id": "new5",
"condition": "data3"
}],
"else": [{
"id": "new6",
"condition": "data4"
}]
}
]
I have to recursively iterate through all existing inner child array of the input json array to formulate the output.
Following is the partially implemented code for the functionality.
ruleJSONFormatter = (request, parentItem, innerJSON) => {
try {
var outerObject = request;
if (outerObject.children && outerObject.children.length) {
var innerArray = outerObject.children;
// second iteration with inner children
innerArray.forEach((innerItem, index) => {
let parentObj = {};
let recursiveObj = {}; let thenArray = [];
recursiveObj['condition'] = innerItem.value && innerItem.value != undefined ? innerItem.value.formatedData : {};
recursiveObj['type'] = innerItem.type;
recursiveObj['id'] = innerItem.id;
recursiveObj['pid'] = innerItem.pid;
if (innerItem.children && innerItem.children != undefined && innerItem.children.length) {
switch (innerItem.type) {
case 'if':
recursiveObj['then'] = [];
recursiveObj['else'] = [];
}
if (Object.keys(parentObj).length == 0) {
parentObj = recursiveObj;
} else {
}
ruleJSONFormatter(innerItem, parentItem, parentObj)
} else {
if (Object.keys(parentObj).length == 0)
responseArray.push(innerJSON);
}
});
}
else {
console.log("No Values Inside the Formated Data ")
}
console.log("output-----------");
console.log(JSON.stringify(responseArray));
return responseArray
} catch (error) {
console.log('((((((((((((((((((((((((((', error)
}
}
final output array has a condition key which binds the value key from the input json and 'then' key which contains the multiple successive inner children array which is the success condition for type 'if' object. similar is the case for 'else' key in output
I find it hard to recursively call the same function to generate the desired output. the problem arises when there are deep nesting in the children array.Any help is appreciated.Thanks.