Is there any way in dustjs to iterate through array and get the number of occurrence?
I am trying to get the count of type='MOBILE' from the JSON data below:
[
{
"type": "MOBILE",
"formattedPhoneNumber": "5123 4566"
},
{
"type": "MOBILE",
"formattedPhoneNumber": "5123 4568"
},
{
"type": "MOBILE",
"formattedPhoneNumber": "5123 4568"
},
{
"type": "LANDLINE",
"formattedPhoneNumber": "5123 4568"
}
]
here I am expecting a count of 3 from above example where type is 'MOBILE'.
You can write a simple helper to do this for you. A helper transforms data from your context in a specific way. For more information, you can read the documentation on context helpers
{
"numbers": [{ "type": "MOBILE", ... }, { ... }],
"countByKey": function(chunk, context, bodies, params) {
var target = context.resolve(params.target);
var key = context.resolve(params.key);
var value = context.resolve(params.value);
return target.filter(function(item) {
return item[key] === value;
}).length;
}
}
Then you can use your helper in a template like this:
{#countByKey target=numbers key="type" value="MOBILE"}You have {.} mobile numbers{/countByKey}
Related
I am trying to filter some articles from a graphql response, by articleTag. Se my structure below:
{
"id": "41744081",
"articleTitle": "text",
"articleContent": "text",
"categoryName": { "categoryName": "Company", "id": "38775744" },
"articleTags": [
{ "articleTag": "event", "id": "37056861" },
{ "articleTag": "car", "id": "37052481" },
]
},
{
"id": "41754317",
"articleTitle": "text",
"articleContent": "text",
"categoryName": { "categoryName": "Sales and Martketing", "id": "38775763" },
"articleTags": [{ "articleTag": "technology", "id": "37056753" }]
},
...
But when applying my function:
notificationFiltered () {
var articleResponse = this.response.allArticles;
var routeParam = this.$route.params.tagName; //contains the id of the tag
const filteredTag = articleResponse.filter((item) => {
return (item.articleTags.indexOf(routeParam) >= 0);
});
console.log(filteredTag);
},
When I'm "console.log" the result I get only a "[]". Not sure if is related with the way of query is being render, in the API I get the same formation but with this slightly difference
{
"data": {
"allArticles": [... the specify structure above]
}
}
while printing that with vue {{response.allArticles}} I just get the first structure, I think it shouldn't matter?
Thanks in advance for the advice
You won't be able to use indexOf for array of objects to find a matching object - only strict equality is needed, and that's hard to get in the reference land. Consider this:
const objs = [
{ foo: 'bar' },
{ foo: 'baz' },
{ foo: 'foo' } // whatever
];
const needle = { foo: 'baz' };
objs.indexOf(needle);
// -1
What? Yes, there's an object looking exactly like needle in that array - but it's a different object:
objs[1] === needle; // false
That's why indexOf just goes past that one - and gives out -1, a "not found" result.
What you should be able to use in this case is findIndex. Still you need to build the predicate to have a match. For example:
const objs = [
{ foo: 'bar' },
{ foo: 'baz' },
{ foo: 'foo' }
];
const needle = { foo: 'baz' };
objs.findIndex(el => JSON.stringify(el) === JSON.stringify(needle));
// 1
In this example, comparing results of JSON.stringify in the predicate function is a poor man's _.isEqual - just to illustrate the concept. What you should consider actually using in your code is either _.isEqual itself, or similar function available in toolkit of your choice.
Alternatively, you can just check for specific fields' values:
objs.findIndex(el => el.foo === needle.foo); // still 1
This will apparently find objects even if their other properties do not match though.
I am trying to figure out an easy way to convert an array of objects to an object
I have an array of objects that looks like this:
[
{
"id": "-LP9_kAbqnsQwXq0oGDT",
"value": Object {
"date": 1541482236000,
"title": "First",
},
},
.... more objects here
]
And id like to convert it to an object with the timestamps as the keys, and arrays of objects corresponding to that date. If that key already exists, then add the object to the corresponding array associated with that key
{
1541482236000:
[{
"id": "-LP9_kAbqnsQwXq0oGDT",
"value": Object {
"date": 1541482236000,
"title": "First",
},
},
{
"id": "-LP9_kAbqnsQwXqZZZZ",
"value": Object {
"date": 1541482236000,
"title": "Some other title",
},
},
.... more objects here
],
1541482236001:
[{
"id": "-LP9_kAbqnsQ1234",
"value": Object {
"date": 1541482236001,
"title": "Another title",
},
},
.... more objects here
]
}
I was able to achieve something similar using reduce. However it does not handle adding objects to the array when their key already exists.
calendarReminders = action.value.reduce((obj, reminder) => {
dateKey = moment(reminder.value.date).format('YYYY-MM-DD')
obj[dateKey] = [reminder]
return obj;
}, {});
How can I do this?
You just need to check whether the object is already a key and if not add it with the value of an array. Then you can just push() into it:
let arr = [{"id": "-LP9_kAbqnsQwXq0oGDT","value": {"date": 1541482236000,"title": "First",},},{"id": "SomID","value": {"date": 1541482236000,"title": "Some other title",},},{"id": "A different ID","value": {"date": 1541482236001,"title": "A third title",},}]
let calendarReminders = arr.reduce((obj, reminder) => {
(obj[reminder.value.date] || (obj[reminder.value.date] = [])).push(reminder)
return obj;
}, {});
console.log(calendarReminders)
If you want to set the keys to a different format with moment, you should be able to do that without changing the basic idea.
Please test the below code!
First you iterate through your array of data,
if your result object/dictionary already has the key then you just add the current item
otherwise you make the key and set the value
const data = [];
let result = {};
for (const item of data) {
const key = item.value.date;
if (result.hasOwnProperty(key)) {
const prevData = result[key];
result[key] = [...prevData, item];
} else {
result[key] = [item];
}
}
I am having many such entries in my json data. The "type" consists of tw attributes i.e. income and expense. How to print the "label" which have type="expense" in using JavaScript.
This json data below is just an example.
Check the image to get a better idea of json data.
"expenses_veterinary":{
label:"Veterinary, breeding, and medicine"
name:"expenses_veterinary"
total:0
type:"expense"
}
console.log($ctrl.gold_standard_categories); prints all the json data.
I tried the code written below but its not working.
if($ctrl.gold_standard_categories.name.type=expense){
console.log($ctrl.gold_standard_categories.label);
}
It prints all the data because of the single equals sign in your if statement.
It means you are always trying to assign the value "expense" to your type property and so the if statement will always evaluate to true.
What you are intending to do is compare the values, not assign a value.
https://jsfiddle.net/yxL4rpj2/
assume that in var money you store the json response
var grouppedMoney = {
expenses: [],
incomes: []
};
for(var i = 0; i <= money.length - 1; i++){
for(moneyType in money[i]){
var _typeString = money[i][moneyType].type == 'expense' ? 'expenses' : 'incomes';
grouppedMoney[_typeString].push(money[i][moneyType]);
}
}
Here is the basic example.Iterate over your object and see type value is equal to expense then print the label value.
var data = {
"expenses_veterinary":{
"label":"Veterinary, breeding, and medicine",
"name":"expenses_veterinary",
"total":0,
"type":"income"
},
"expenses_car":{
"label":"bus and truck",
"name":"expenses_car",
"total":0,
"type":"expense"
}
};
for (var property in data) {
if (data.hasOwnProperty(property)) {
// do stuff
if(data[property]['type']=='expense'){
console.log(data[property]['label']);
}
}
}
It seems you are using AngularJS ($ctrl) so you may consider using either native angular filters or custom filter to do this.
BTW, using vanilla JS, this simple loop will work :
for(var key in jsonData) {
if("expense" === jsonData[key]["type"]) {
console.log(jsonData[key]["label"]);
}
}
Sample snippet
var jsonData = {
"expensesigoods": {
"name": "expenses_goods",
"label": "Cost of goods sold",
"type": "expense",
"total": 0
},
"expensesicar": {
"name": "expenses_car",
"label": "Car and truck expenses",
"type": "expense",
"total": 0
},
"expensesichemicals": {
"name": "expenses_chemicals",
"label": "Chemicals",
"type": "expense",
"total": 0
},
"expensesiconservation": {
"name": "expenses_conservation",
"label": "Conservation expenses",
"type": "other",
"total": 0
}
}
for(var key in jsonData) {
if("expense" === jsonData[key]["type"]) {
console.log(jsonData[key]["label"]);
}
}
Try Array.filter() method to filter the data based on type="expense".
Working Fiddle
var obj = {
"expenses_goods":{
"label":"expenses_goods",
"name":"expenses goods",
"total":0,
"type":"income"
},
"expenses_cars":{
"label":"expenses_cars",
"name":"expenses cars",
"total":0,
"type":"expense"
},
"expenses_veterinary":{
"label":"expenses_veterinary",
"name":"expenses veterinary",
"total":0,
"type":"income"
}
};
var res = Object.keys(obj).filter(item => { return obj[item].type == 'expense' });
for (var i in res) {
document.getElementById("result").innerHTML = obj[res[i]].label;
}
<div id="result">
</div>
This is the sample json:
{
"search": {
"facets": {
"author": [
],
"language": [
{
"value": "nep",
"count": 3
},
{
"value": "urd",
"count": 1
}
],
"source": [
{
"value": "West Bengal State Council of Vocational Education & Training",
"count": 175
}
],
"type": [
{
"value": "text",
"count": 175
}
],
}
}
There are several ways to delete key search.facets.source:
delete search.facets.source
delete jsobObj['search']['facets']['source']
var jsonKey = 'source';
JSON.parse(angular.toJson(jsonObj), function (key, value) {
if (key != jsonKey)
return value;
});
Above 1 & 2 are not dynamic, and 3 is one of the way but not a proper way. Because if source is present in another node then it will not work. Please anybody can tell me how to delete it dynamically in any kind of nested key. Because we can not generate sequence of array dynamically in above 2.
Assuming you're starting from this:
let path = 'search.facets.source';
Then the logic is simple: find the search.facets object, then delete obj['source'] on it.
Step one, divide the path into the initial path and trailing property name:
let keys = path.split('.');
let prop = keys.pop();
Find the facets object in your object:
let parent = keys.reduce((obj, key) => obj[key], jsonObj);
Delete the property:
delete parent[prop];
I have found out another solution, it is very easy.
var jsonKey = 'search.facets.source';
eval('delete jsonObj.' + jsonKey + ';');
I have 2 array objects in Angular JS that I wish to merge (overlap/combine) the matching ones.
For example, the Array 1 is like this:
[
{"id":1,"name":"Adam"},
{"id":2,"name":"Smith"},
{"id":3,"name":"Eve"},
{"id":4,"name":"Gary"},
]
Array 2 is like this:
[
{"id":1,"name":"Adam", "checked":true},
{"id":3,"name":"Eve", "checked":true},
]
I want the resulting array after merging to become this:
[
{"id":1,"name":"Adam", "checked":true},
{"id":2,"name":"Smith"},
{"id":3,"name":"Eve", "checked":true},
{"id":4,"name":"Gary"},
]
Is that possible? I have tried angular's array_merge and array_extend like this:
angular.merge([], $scope.array1, $scope.array2);
angular.extend([], $scope.array1, $scope.array2);
But the above method overlap the first 2 objects in array and doesn't merge them based on matching data. Is having a foreach loop the only solution for this?
Can someone guide me here please?
Not sure if this find of merge is supported by AngularJS. I've made a snippet which does exactly the same:
function merge(array1, array2) {
var ids = [];
var merge_obj = [];
array1.map(function(ele) {
if (!(ids.indexOf(ele.id) > -1)) {
ids.push(ele.id);
merge_obj.push(ele);
}
});
array2.map(function(ele) {
var index = ids.indexOf(ele.id);
if (!( index > -1)) {
ids.push(ele.id);
merge_obj.push(ele);
}else{
merge_obj[index] = ele;
}
});
console.log(merge_obj);
}
var array1 = [{
"id": 1,
"name": "Adam"
}, {
"id": 2,
"name": "Smith"
}, {
"id": 3,
"name": "Eve"
}, {
"id": 4,
"name": "Gary"
}, ]
var array2 = [{
"id": 1,
"name": "Adam",
"checked": true
}, {
"id": 3,
"name": "Eve",
"checked": true
}, ];
merge(array1, array2);
Genuinely, extend in Angular works with object instead of array. But we can do small trick in your case. Here is another solution.
// a1, a2 is your arrays
// This is to convert array to object with key is id and value is the array item itself
var a1_ = a1.reduce(function(obj, value) {
obj[value.id] = value;
return obj;
}, {});
var a2_ = a2.reduce(function(obj, value) {
obj[value.id] = value;
return obj;
}, {});
// Then use extend with those two converted objects
var result = angular.extend([], a1_, a2_).splice(1)
Notes:
For compatibility, reduce may not work.
The after array will replace the previous one. This is because of implementation of extend in Angular.