I am fetching notifications using API. Now here is the scenario:
1- I called the API, got 2 records and stored them in local variable (notifications) to show in view.
[{"id": 1, "notification": "bla"}, {"id": 2, "notification": "bla bla"}]
2- I am calling the same API to check for new notification after every 5 seconds. This time I need to compare the API response with the local variable, so if no new notification (different id) is in the record, don't push in local variable, other push.
I have tried something like this:
var val = JSON.parse(data);
if( val.length > 0 ) {
for( var i = 0; i < val.length; i++ ) {
this.notifications.forEach(element => {
if( element.id != val[i].id ) {
this.notifications.push(val[i]);
}
});
}
}
But its adding duplicate records. Any help would be appreciated.
Thanks
You need to use Array.find() to find the duplicate object in the val array.
var notifications = [{"id": 1, "notification": "bla"}, {"id": 2, "notification": "bla bla"}];
var data = `[{"id": 1, "notification": "bla"}, {"id": 4, "notification": "bla bla bla"}]`
var val = JSON.parse(data);
if( val.length > 0 ) {
val.forEach((obj)=>{
var existNotification = notifications.find(({id}) => obj.id === id);
if(!existNotification){
notifications.push(obj);
}
});
}
console.log(notifications);
Currently, you are getting duplicated element because the id value is compared against all the existing id values in notifications array. So, if one of the id do not match with another, it is pushed immediately into the notifications array. So, the better way and simple way is to use a find operation on the array to check the existing object.
A more robust way to handle this could be by using map in JS.
Rather than iterating the notifications (size = m) for every object in the data (size = n) would result in more time complexity of O(m x n).
Hence it could be done in O(n) as below:-
var notifications = new Map();
// assuming you get this at the beginning
var data1 = `[{"id": 1, "notification": "bla"}, {"id": 2, "notification": "bla bla"}]`;
checkAndAddNotification(data1);
// assuming you get this at the second time
var data2 = `[{"id": 1, "notification": "bla"}, {"id": 4, "notification": "bla bla bla"}]`
checkAndAddNotification(data2);
function checkAndAddNotification(data){
var val = JSON.parse(data);
if (val){
val.forEach((obj)=>{
var existNotification = notifications.get(obj.id);
if(!existNotification){
notifications.set(obj.id, obj);
}
});
}
}
console.log(notifications);
notifications.forEach((notification) => console.log(notification));
Please open the browser console as well while running the code.
Even if you plan to iterate over the map, the order would be preserved in the order the objects were inserted. Please look here for more.
Related
I am writing Guild Wars 2 commands into my bot and I have a wallet command which looks up ID's against an endpoint to give each ID a name. What I would like to do is instead of just displaying the name, I would like to display an emoji of each thing. For example, karma symbol for karma, gem symbol for gems. Adding emojis is easy, I get that part, however I can't wrap my head around how to identify what each line in the output is going to be as it is different per account that is looked up.
Here is my code so far:
var newArray = [];
for (var i = 0; i < walletArray.length; i++) {
for (var x = 0; x < currencyArray.length; x++) {
if (walletArray[i].id === currencyArray[x].id) {
if (currencyArray[x].name === "Coin") {
var bronze = String(walletArray[i].value).slice(-2)
var silver = String(walletArray[i].value).slice(-4, -2)
var gold = String(walletArray[i].value).slice(0, -4)
}
newArray.push(`${currencyArray[x].name} - ${walletArray[i].value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`)
}
}
}
The walletArray (or part of it) is:
[
{
"id": 1,
"value": 57636
},
{
"id": 2,
"value": 32969
},
{
"id": 3,
"value": 36
}
]
The currencyArray is:
{
"id": 1,
"name": "Coin",
"description": "The primary currency of Tyria. Spent at vendors throughout the world.",
"order": 101,
"icon": "https://render.guildwars2.com/file/98457F504BA2FAC8457F532C4B30EDC23929ACF9/619316.png"
},
{
"id": 2,
"name": "Karma",
"description": "Earned through various activities. Spent at vendors throughout the world.",
"order": 102,
"icon": "https://render.guildwars2.com/file/94953FA23D3E0D23559624015DFEA4CFAA07F0E5/155026.png"
},
{
"id": 3,
"name": "Laurel",
"description": "Earned through the Log-in Reward Chest. Spent in major cities. Used to purchase various rewards.",
"order": 104,
"icon": "https://render.guildwars2.com/file/A1BD345AD9192C3A585BE2F6CB0617C5A797A1E2/619317.png"
}
The output is:
Wallet command output
I have no idea if I am even approaching this correctly but I just want it to look a bit nicer! It is fully functional just we can always improve things. My JS is not the best, it was learned during lockdown as something to do and was learned almost entirely from this website!
Any help would be appreciated, cheers.
Well, if I understand your problem correctly, you know each line of the output is gonna be, because of currencyArray.name. The solution should be something like:
var newArray = [];
for (var i = 0; i < walletArray.length; i++) {
for (var x = 0; x < currencyArray.length; x++) {
if (walletArray[i].id === currencyArray[x].id) {
var emote;
if (currencyArray[x].name === "Coin") {
emote = "🪙"
var bronze = String(walletArray[i].value).slice(-2)
var silver = String(walletArray[i].value).slice(-4, -2)
var gold = String(walletArray[i].value).slice(0, -4)
}
else if (currencyArray[x].name === "Karma") {
emote = "☯️"
}
else if (currencyArray[x].name === "Laurel") {
emote = "💳"
}
newArray.push(`${emote} ${currencyArray[x].name} - ${walletArray[i].value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`)
}
}
}
Of course, use any emotes you wish.
Maybe you want to use a Map. discord.js names it Collection but they are pretty much the same.
let myMap = new Map();
myMap.set('key', 'emoji')
let emoji1 = myMap.get('key') //'emoji'
The 'key' is linked to the value which you can get with the Map.get method
I pretty new to angular and I have a question.
I need 2 arrays for ng2-charts, one with labels and one with data.
I make http request to AWS and I got this json
{
"System1": [
{
"name": "MF3",
"descr": "Multifilo MF3",
"speed": [1,2,3,4],
"time": ["10.01", "10.02", "10.03", "10.04"]
}
]
}
I assing all the result to result: Array<SystemModel>;
For use speed and time on ng2-charts I have to copy the two array speed and time on new array: public lineChartSpeed: Array<number> = []; and public lineChartTime: Array<any> = [];
How can I copy this 2 array on my new array? I know how to access to data only on html template, but not on typscript file...
My component is:
public lineChartSpeed: Array<number> = [];
lineChartTime: Array<any> = [];
result: Array<ImpiantoModel>;
getdata() {
this.http.get<SystemModel[]>(this.myUrl)
.subscribe(
data => { this.result = data;
// perform the copy of speed and time on lineChartTime and lineChartSpeed
});
}
How can I copy the array?
If you need more details, please ask in the comments!
thank you !
var system1 = {
"System1": [
{
"name": "MF3",
"descr": "Multifilo MF3",
"speed": [1,2,3,4],
"time": ["10.01", "10.02", "10.03", "10.04"]
}
]
}
var speed = system1.System1[0].speed
var time = system1.System1[0].time
console.log('Array of Speed', speed)
console.log('Array of Time', time)
//Merge or concatenate two Arrays
var newArray = [...speed, ...time]
console.log('Merged or concatenated Arrays', newArray)
Use slice operator to create a new copy of the array
this.result = data.slice();
this.lineChartSpeed = [].concat(this.result[0].speed);
this.lineChartTime = [].concat(this.result[0].time);
Why does this ES multi-match query return a 400 error (bad request)?
"query": {
"multi_match": {
"query": searchTerms,
"fields": ["content", "title"],
"operator": "and"
}
},
size: 100,
from: 0,
highlight: {
fields: {
"title": {number_of_fragments: 0},
"content": {number_of_fragments: 10,fragment_size: 300}
}
}
}
I'm using this query in conjunction with AngularJS UI Bootstrap Typeahead code like this
uib-typeahead="query as query._source.ymme for query in getSuggestions($viewValue)" typeahead-on-select="search($item)"
This is my search() function
$scope.search = function() {
console.log($scope.searchTerms);
$scope.currentPage = 0;
$scope.results.documents = [];
$scope.isSearching = true;
return searchService.search($scope.searchTerms, $scope.currentPage).then(function(es_return) {
var totalItems = es_return.hits.total;
var totalTime = es_return.took;
var numPages = Math.ceil(es_return.hits.total / $scope.itemsPerPage);
$scope.results.pagination = [];
for (var i = 1; i <= 100; i++) {
if(totalItems > 0)
$scope.results.totalItems = totalItems;
$scope.results.queryTime = totalTime;
$scope.results.pagination = searchService.formatResults(es_return.hits.hits);
$scope.results.documents = $scope.results.pagination.slice($scope.currentPage, $scope.itemsPerPage);
}
}
),
function(error){
console.log('ERROR: ', error.message);
$scope.isSearching = false;
}
};
I'm not quite sure what is wrong? I'm thinking it has something to do with $scope, but I'm not sure. The query works when I use it Sense plugin for ES and it also works if I just type in a search term instead of selecting it from the autocomplete dropdown.
If it is $scope, what am I missing?
UPDATE
All shards failed for phase: [query_fetch]
org.elasticsearch.search.SearchParseException: [hugetestindex][0]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"query":{"multi_match":{"query":{"_index":"hugetestindex","_type":"doc","_id":"57","_score":3.877801,"_source":{"ymme":"bourne supremacy"}},"fields":["content","title"],"operator":"and"}},"size":100,"from":0,"highlight":{"fields":{"title":{"number_of_fragments":0},"content":{"number_of_fragments":10,"fragment_size":300}}}}]]
UPDATE 2 Object {_index: "hugetestindex", _type: "doc", _id: "56", _score: 2.5276248, _source: Object}
I think that is the problem, instead of a search terms, its receiving "Object"....?
UPDATE 3So basically it goes like this,
[Object, Object, Object, Object, Object]
0: Object
_id: "229"
_index: "hugetestindex"
_score: 3.3071127
_source: Object
ymme: "bourne supremacy"
__proto__: Object
_type: "doc"
__proto__:
Object1:
Object2:
Object3:
Object4:
Object
length: 5
__proto__: Array[0]
where "bourne supremacy" is the value of the ymme field in the _source Object, the array at the top with the 5 objects is the es return, es_return.hits.hits - this last hits, is the array.
The way you deconstruct your object is by doing something like the following:
object.data.hits.hits._source.field_name;
The above is only a notation to get the value of a single field, you might need to do a loop for each of those values so maybe something like:
$scope.list = []
for hit in object.data.hits.hits {
$scope.list.push(hit._source.field);
}
console.log(list);
Then from your HTML you want to use this list by doing an ng-repeat with it or something similar to get each of the terms in the list.
<div ng-repeat="term in list">{{term}}</div>
If you can update your question with how your object looks and what data you want from it, I can update this answer to match it exactly.
UPDATE
To match your data structure, I'm assuming you want to extract each of the ymme values from those objects. You need to do the following:
<div ng-repeat="object in es_return.hits.hits">
{{object._source.ymme}}
</div>
Just make sure "es_return" is a $scope variable so you can access it as above or just do:
$scope.es_return = es_return;
In your Angular code
I am fetching data from JSON in my controller and need to convert it into seconds.
[
{
"Id": "0",
"Name": "Subscriber",
"ItemsCount": 5,
"ItemsFailedCount": 6,
"ExecutionStart": "2015-08-01T08:01:00.9748076+01:00",
"ExecutionEnd": "2015-08-01T08:01:00.9748076+01:00"
}
]
What I am trying to achieve is getting the difference between "ExecutionStart" and "ExecutionEnd" in seconds.
I have looked upon for the solution of this on internet and couldn't find any solution unfortunately. So I have nothing to show that I've tried.
Kindly help.
First create Date objects from the date strings:
var executionStart = new Date(data[0].ExecutionStart);
var executionEnd = new Date(data[0].ExecutionEnd);
Then subtract the dates and divide by 1000 because difference will be in milliseconds and there are 1000 milliseconds in a second.
var diffSeconds = (executionEnd - executionStart) / 1000;
JsFiddle
solution using date.parse();
var data = [
{
"Id": "0",
"Name": "Subscriber",
"ItemsCount": 5,
"ItemsFailedCount": 6,
"ExecutionStart": "2015-08-01T08:01:00.9748076+01:00",
"ExecutionEnd": "2015-08-01T08:01:10.9748076+01:00"
}
];
var executionStarts = Date.parse(data[0].ExecutionStart);
var executionEnds = Date.parse(data[0].ExecutionEnd);
var diffSeconds = (executionEnds - executionStarts)/1000;
alert(diffSeconds);
Let's say I have this Json ..
{
"name": "Mark",
"gender": "male",
"account1": {
"accountNo": 1201,
"balance": 300
},
"account2": {
"accountNo": 1354,
"balance": 5000
}
}
What I expect is like ..
$scope.myArray = [
{
"accountNo": 1201,
"balance": 300
},
{
"accountNo": 1354,
"balance": 5000
}
];
In AngularJS, how can I pick some part of Json data and push it into an array iteratively( I mean, when I have account1, account2 account3 or more, it can still add them into the array).
You could normally just assign the array over, but in this scenario that is not an option because your array is psuedo.
Ideally you would like to be able to do what this answer (related question) does: How to return and array inside a JSON object in Angular.js which is simply
$scope.myArray = json.accounts;
However, as noted, you do not have an accounts array so you need to make one.
var accounts = [];
for(var key in json){
if( !json.hasOwnProperty(key) // skip prototype extensions
|| !json[key].hasOwnProperty("accountNo") //skip non account objects
) continue;
accounts.push(json[key]);
}
And now you may use this array
$scope.myArray = accounts;
You can access Json data like an array. Like var foo = { ... , 'bar' = 'value', ... } you could get foo value by doing this for['bar']. So, by knowing this, you simply do something like
var arr = [];
for (var i = 0; i < 10; i++) {
arr.push(foo['account'+i]);
}
Although, this has nothing to do with angularjs.