JSON group by key value to new JSON Javascript - javascript

I have been reading some posts which are related to my question, whereas I have not been able to find a proper solution for what I'm trying to do hear.
I have this JSON file that I am obtaining directly from my database via a sql query:
[
{
"scenario": "scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18",
"data": [
{
"date": "2018-05-21",
"price": 14.173041264216105
}
]
},
{
"scenario": "scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
}
]
My objectif is to be able to sort/transform this json object to a new json object which is classified by the scenario, so, something that looks like:
[
{
"scenario": "scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18",
"data": [
{
"date": "2018-05-21",
"price": 14.173041264216105
},
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
},
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
},
{
"scenario": "scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99",
"data": [
{
"date": "2018-05-22",
"price": 42.94691197077433
},
{
"date": "2018-05-22",
"price": 42.94691197077433
}
]
I have been trying some javascript selfmade functions but I have not obtainend the desired result.
This is the last thing I've tried:
let estructura = [];
for (var j =0; j<obj.length; j++){
for (var i=0; i<estructura.length; i++){
if(obj[j]['scenario'] == estructura[i]['scenario']){
estructura[i]['data'].push(obj[j]['data'])
} else {
console.log("no match, we add the scenario to estructura")
estructura.push(
{
scenario:obj[j]['scenario'],
data: []
})
}
}
}
Thank you

You can achieve this easily with built-in functions like reduce. Iterate over the input, grouping into an object indexed by scenario, creating a object with a data array if the scenario doesn't exist yet, and push to that array:
const input=[{"scenario":"scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18","data":[{"date":"2018-05-21","price":14.173041264216105}]},{"scenario":"scenario-483d742c-4492-4a4f-95fa-7ccceac8bb18","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-c705069f-fa53-4ff3-9f07-3fcbf9dc8d15","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99","data":[{"date":"2018-05-22","price":42.94691197077433}]},{"scenario":"scenario-d58bb001-d7ed-4744-8f6c-8377519c7a99","data":[{"date":"2018-05-22","price":42.94691197077433}]}]
console.log(
Object.values(input.reduce((a, { scenario, data }) => {
if (!a[scenario]) a[scenario] = { scenario, data: [] };
a[scenario].data.push(data[0]);
return a;
}, {}))
);

Related

mongodb: How to use variable inside group operator in aggregate operation?

I am tring to make a query where use the value and try to interpolate a string in a new field.
Mongo Database:
[
{
"state": "1",
"events": {
"1": [
{
"date": 123.2,
"msg": "msg1"
},
{
"date": 124.2,
"msg": "msg2"
}
],
"2": [
{
"date": 125.2,
"msg": "msg3"
},
{
"date": 126.2,
"msg": "msg4"
}
],
}
},
{
"state": "2",
"events": {
"1": [
{
"date": 123.2,
"msg": "msg1"
},
{
"date": 124.2,
"msg": "msg2"
}
],
"2": [
{
"date": 125.2,
"msg": "msg3"
},
{
"date": 126.2,
"msg": "msg4"
}
],
}
}
]
Aggregate query:
db.collection.aggregate({
"$match": {
"state": {
"$in": [
"1",
"2"
]
}
}
},
{
"$group": {
"_id": {
"state": "$state"
},
"this_path": {
"$first": {
"$concat": [
"events.",
"$state",
".0.date"
]
}
}
}
})
"this_path" gets "events.1.0.date", but how to use this value, in another query(line), I would like to do like a string interpolation. Some thing like
...
"date": {
"$first": { `\$${this_path}`}
...
so it become the "events.1.date" then "$events.1.0.date" then "123.2"
you can define it by let just for example a fragment from pipeline:
$lookup: {
from: contentCollectionName,
as: 'content',
let: {
parentId: '$id',
},
The id is taken from above matched documents, but it can be anything

Look up values in an array using looping forEach Google Apps Script Javascript

I have an object that looks like the following {key: id numbers}
var obj = {
"c4ecb": {id: [3]},
"a4269": {id: [34,36]},
"d76fa": {id: [54,55,60,61]},
"58cb5": {id: [67]}
}
How do I loop each above id in the following array, and return the label?
var response =
{
"success": true,
"data": [
{
"key": "c4ecb",
"name": "fruits",
"options": [
{
"label": "strawberry",
"id": 3
},
{
"label": "apple",
"id": 4
},
{
"label": "pineapple",
"id": 5
},
{
"label": "Other",
"id": 31
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "a4269",
"name": "vegetables",
"options": [
{
"label": "lettuce",
"id": 34
},
{
"label": "cucumber",
"id": 35
},
{
"label": "radish",
"id": 36
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "d76fa",
"name": "pasta",
"options": [
{
"label": "spaghetti",
"id": 54
},
{
"label": "rigatoni",
"id": 55
},
{
"label": "linguine",
"id": 56
},
{
"label": "lasagna",
"id": 60
},
{
"label": "fettuccine",
"id": 61
}
],
}
]
}
Finally, what I want to do is look up the key and return a string of id values.
For example, input c4ecb and output strawberry. Input a4269 and output lettuce, radish. Input d76fa and output "spaghetti, rigatoni, lasagna, fettuccine"
I think to join the multiple labels output into one string I could use something like
array.data.vegetables.map(vegetables => vegetables.value).join(', ')].toString();
So in the end I want to have something like
var fruits = [some code that outputs "strawberry"];
var vegetables = [some code that outputs "lettuce, radish"];
var pasta = [some code that outputs "spaghetti, rigatoni, lasagna, fettuccine"];
What I've tried so far:
The following loop will return the id only if there is one id to be called for: e.g. only in case one where {id: 3} but returns null in cases like {id: 34,36} (because it's looking for '34,36' in id, which doesn't exist - I need to look for each one individually.
response.data.forEach(({key, options}) => {
if (obj[key]) {
options.forEach(({id, label}) => {
if (id == obj[key].id) obj[key].label = label;
});
}
});
console.log(obj)
Filter the response object to focus on the category that matches the id.
Map over the options array and select the items which appear in obj[id].
Finally convert the filtered results to a string.
See filteredLabelsAsString() function below for implementation.
var obj = {
"c4ecb": {"id": [3]},
"a4269": {"id": [34,36]},
"d76fa": {"id": [54,55,60,61]},
"58cb5": {"id": [67]}
}
var response =
[{
"success": true,
"data": [
{
"key": "c4ecb",
"name": "fruits",
"options": [
{
"label": "strawberry",
"id": 3
},
{
"label": "apple",
"id": 4
},
{
"label": "pineapple",
"id": 5
},
{
"label": "Other",
"id": 31
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "a4269",
"name": "vegetables",
"options": [
{
"label": "lettuce",
"id": 34
},
{
"label": "cucumber",
"id": 35
},
{
"label": "radish",
"id": 36
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "d76fa",
"name": "pasta",
"options": [
{
"label": "spaghetti",
"id": 54
},
{
"label": "rigatoni",
"id": 55
},
{
"label": "linguine",
"id": 56
},
{
"label": "lasagna",
"id": 60
},
{
"label": "fettuccine",
"id": 61
}
],
}
]
}];
function filteredLabelsAsString(obj_key, obj, content=response) {
// sanity check: obj must contain obj_key
if (Object.keys(obj).includes(obj_key)) {
return content.filter((item) => {
// filter content using value of obj_key
return item.data[0].key == obj_key;
}).map((item) => {
// item : { success: true, data: [] }
// map over options array
return item.data[0].options.map((opt) => {
// option : {id, label}
// return the label if the id is in the obj object's list
if (obj[item.data[0].key].id.includes(opt.id))
return opt.label;
}).filter((label) => {
// filter out empty items
return label !== undefined;
});
}).join(",");
}
// if obj does not contain obj_key return empty string
return "";
}
console.log("fruits: " + filteredLabelsAsString("c4ecb", obj));
console.log("vegetables: " + filteredLabelsAsString("a4269", obj));
console.log("pasta: " + filteredLabelsAsString("d76fa", obj));

Unexpected data sorting result after filtering from parent and child node

I have list of tree node metadataList Like below:
[
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
}
]
},
{
"data": {
"metadata": {
"category": [
"Isv"
]
}
},
"children": [
{
"data": {
"metadata": {
"category": [
"Isv"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Isv"
]
}
},
"children": [
]
}
]
},
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
]
}
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Isv"
]
}
},
"children": [
]
}
]
},
{
"data": {
"metadata": {
"category": [
"Incentives"
]
}
},
"children": [
{
"data": {
"metadata": {
"category": [
"Incentives"
]
}
},
"children": [
]
}
]
}
]
Which is a type of array of data and children collection it's class like below:
export default class CurrentTopicMetadataTreeNode {
public data: CurrentTopicMetadata;
public children: CurrentTopicMetadataTreeNode[];
}
export default class CurrentTopicMetadata {
public id: string;
public metadata: TopicMetadata
}
export class TopicMetadata {
public category: Category[]
}
export enum Category {
Csp = 'Csp',
Mpn = 'Mpn',
Incentives = 'Incentives',
Referrals = 'Referrals',
Isv = 'Isv',
}
What I am trying, to filter list as data and children order as per category. Let say if filter by a category all data and children belongs to that category should come like below order.
But I am getting data like this order :
One Element On Array Problem Set:
Here in this array if I search with Csp Only data in root node which is Csp and data in children only has one data which contains Csp would be in array.
[{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
},
{
"data": {
"metadata": {
"category": [
"Mpn"
]
}
},
"children": [
]
}
]
}]
Expected Output: So after filtered by Csp node should be look like this:
[
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
{
"data": {
"metadata": {
"category": [
"Csp"
]
}
},
"children": [
]
}
]
}
]
here is my code, where I am doing wrong?
// Rule 1 check parent metadata category whether be empty
// Rule 2 and 3
function find_in_children(children, parent_category) {
children_has_same_category = []
for(var i in children) {
let child = children[i];
if(child.children != undefined && child.children.length > 0 && child.data.metadata.category == parent_category) {
children_has_same_category.push(child);
}
}
if(children_has_same_category.length > 0) {
return children_has_same_category
} else {
for(var i in children) {
let child = children[i];
return find_in_children(child.children, parent_category);
}
}
}
function check_object(object) {
let parent_category = object.data.metadata.category[0];
if(object.children != undefined && object.children.length > 0) {
return {'data': object.data, 'children': find_in_children(object.children, parent_category)}
} else {
return {'data': object.data}
}
}
function apply_rules(object) {
// Rule 1 check parent metadata category whether be empty
if(object.data.metadata.category.length > 0) {
return {'data': object.data}
} else {
return check_object(object)
}
}
target = {
value: 'Isv'
}
filtered_datas = []
for(var i in datas) {
let data = datas[i];
if(data.data.metadata.category.length > 0) {
result = apply_rules(data)
if(result.data.metadata.category[0] == target.value) {
filtered_datas.push(result);
}
}
}
Here is the data sample and result: https://jsfiddle.net/faridkiron/b02cksL8/#&togetherjs=F7FK3fBULx
I have resolve above problem like below way:
const findMatchedChild = (nodeInList, type) => {
const node = Object.assign({}, nodeInList)
node.children = nodeInList.children
.filter(child => child.data.metadata.category.includes(type))
.map(child => findMatchedChild(child, type))
return node
}
const cspList = findMatchedChild({ children: data }, 'Csp').children
console.log(JSON.stringify(cspList, null, 2));
Got the expected result.

filter on the basis of a value in an array in where

I'm querying data, where the structure is something like this.
I have two models, FoodDrinks and Cuisines. They have many to many relation.
Now on the following query
{
"filter": {
"include": "cuisines"
}
}
I am getting the following results.
[
{
"id": 1,
"name": "Biryani",
"cuisines": [
{
"id": 1,
"name": "Mughlai"
},
{
"id": 2,
"name": "North Indian"
},
{
"id": 3,
"name": "Afghani"
}
]
},
{
"id": 2,
"name": "Chhole Bhature",
"cuisines": [
{
"id": 2,
"name": "North Indian"
}
]
},
{
"id": 3,
"name": "Amritsari Naan",
"cuisines": [
{
"id": 2,
"name": "North Indian"
},
{
"id": 6,
"name": "Punjabi"
},
]
}
]
Now I want only those food drinks which have cuisines from the following array.
let cuisinesIDs = ["1", "2"]
What will the following query for that?
I guess something like the below should work:
{
"filter": {
"include": "cuisines"
},
"where": {
"cuisines.id": {
"inq": cuisinesIDs
}
}
}
It might be the same answer as #Behrooz, but I would try:
{
"filter": {
"include": {
relation: 'cuisines',
scope: {
where: {
id: {inq: cuisinesIDs}
}
}
}
}
}

angularjs append value into inside array

I am having array in below format. i am having issue to append the value inside each chapter array. i need to add field like 'checked:true'. I need to get the data in same format. Expectation is, need same format with added one field inside chapter array.
{
"Books": [
{
"label":"Book1",
"data": [
{
"bookId": 3561,
"bookName": "AJ200",
"chapters": [
{
"id": 3926,
"name": "red"
},
{
"id": 3927,
"name": "yellow"
},
{
"id": 3928,
"name": "black"
}
]
}
]
},
{
"label":"Book2",
"data":[
{
"bookId": 3561,
"bookName": "AJ200",
"chapters": [
{
"id": 3564,
"name": "blue"
},
{
"id": 3565,
"name": "orange"
}
]
}
]
}
]
}
after adding field chapters array looks like as below,
"chapters": [
{
"id": 3564,
"name": "blue",
"checked":true
},
{
"id": 3565,
"name": "orange"
"checked":true
}
This is a little verbose but works all the same!
var myObject =
{
"Books": [
{
"label":"Book1",
"data": [
{
"bookId": 3561,
"bookName": "AJ200",
"chapters": [
{
"id": 3926,
"name": "red"
},
{
"id": 3927,
"name": "yellow"
},
{
"id": 3928,
"name": "black"
}
]
}
]
},
{
"label":"Book2",
"data":[
{
"bookId": 3561,
"bookName": "AJ200",
"chapters": [
{
"id": 3564,
"name": "blue"
},
{
"id": 3565,
"name": "orange"
}
]
}
]
}
]
}
var books = myObject.Books;
for(var i=0; i<books.length; i++) {
var bookData = books[i].data;
for(var j=0;j<bookData.length;j++) {
var chapters = bookData[j].chapters;
for(var k=0;k<chapters.length;k++) {
chapters[k].checked = true;
}
}
}
console.log(JSON.stringify(books));

Categories