extract data from array with javascript - javascript

I'm creating a google chrome extension that will use some data that are stored inside a JSON file. I need to compose a team of 11 members that needs to be extracted from the processed JSON file, but I don't know how to proceed. After I've parsed the file, I want that for every team position there are only x team members. For example, I need to randomly select one Goalkeeper, three, four or five defenders, three four or five midfield and one, two or three attackers. With PHP I'm able to do that without problems, but I'm not very experienced with javascript and I need help. Is there any function or any way to achieve this?
JSON
{
"player_id":3,
"player_surname":"Immobile",
"player_name":"Ciro",
"player_number":17,
"team_name":"Lazio",
"team_abbreviation":"LAZ",
"role_abbreviation":"A",
"role_name":"Attaccante",
"quotation":62,
}
JS
const uri = 'api/players_.json';
$.getJSON(uri, function(data){
// code stuff here
});

A combination of reduce, map and filter can be used to setup teams:
const players = [
{
"player_id":3,
"player_surname":"Immobile",
"player_name":"Ciro",
"player_number":17,
"team_name":"Lazio",
"team_abbreviation":"LAZ",
"role_abbreviation":"A",
"role_name":"Attaccante",
"quotation":62,
},
{
"player_id":3,
"player_surname":"Immobile",
"player_name":"Ciro",
"player_number":17,
"team_name":"Lazio",
"team_abbreviation":"BLAA",
"role_abbreviation":"A",
"role_name":"Attaccante",
"quotation":62,
}
];
const playersPerTeam = Object.values(players.reduce((acc, player) => {
const teamKey = player.team_abbreviation;
if(!acc.hasOwnProperty(teamKey)){
acc[teamKey] = [];
}
acc[teamKey].push(player);
return acc;
}, {}));
const chosenSetupPerTeam = playersPerTeam.map(playersInTeam => {
const playersNeededPerRole = {
"Portiere": 1, // Keeper
"Difensore": 4, // Defender
"Centrocampista": 4, // midfielder
"Aggressore": 2, // Attacker
};
const playersPresentPerRole = {};
// Get a team to fulfil the requirements stated in playersNeededPerRole
return playersInTeam.filter(player => {
// Role does not exist, thus the player can't join the team
if(!playersNeededPerRole.hasOwnProperty(player.role_name)){
return false;
}
// Set the default of players present per role to 0
if(!playersPresentPerRole.hasOwnProperty(player.role_name)){
playersPresentPerRole[player.role_name] = 0;
}
// Stop if all positions have been filled as specified in playersNeededPerRole
if(playersPresentPerRole[player.role_name] === playersNeededPerRole[player.role_name]){
return false;
}
playersPresentPerRole[player.role_name]++;
return true;
});
});
console.log(chosenSetupPerTeam)
Checkout the demo

Related

Using PerformanceObserver API to get and save data for further usage with classes - JS

I want to get data provided by PerformanceObserver and use it in my app.
In my case, I want to get data from PerformanceObserver that responsible only for css files and do something (in this case just check if these resources are cached or not)
Here's the code example:
class Styles {
static getStyleResources() {
const styles = [];
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if(entry.initiatorType === 'css') {
styles.push(entry);
return styles;
}
}
});
po.observe({ type: 'resource', buffered: true });
}
static isChached() {
return Styles.getStyleResources().forEach(item => item.transferSize ?
console.log("The data is cached") :
console.log("The data is not cached")
)
}
}
I also tried different approaches but nothing worked. What is the problem and am I going in the right way?
PerformanceObserver works asynchrounously, so you can't directly extract the values of the styles array, since it is a continuous stream. I think you need to catch it, set a limit for styles length for example.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if(entry.initiatorType === 'css') {
styles.push(entry);
return styles;
if (styles.length === 3) {
console.log(styles) // returns an accessible array with 3 entries
}
}
}
});

Object created from a loop in JavaScript, how to analyse them in a json

I'm a begginer in Javascript and I need to analyse a JavaScript Object generated in a loop to keep one parameter and to save this parameter for all object generated in the loop.
This is my program
var onvif = require('onvif');
var fs = require('fs');
var nombrecamera=0;
var taille=0;
var test ='';
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
var STREAM = fs.createWriteStream('STREAM.txt',{flags:'r+'});
onvif.Discovery.on('device', function(cam,rinfo,xml){
// function will be called as soon as NVT responses
nombrecamera+=1;
console.log(cam);
test += cam;
cam2= JSON.stringify({cam}, null , ' ');
//console.log(cam2);
STREAM.write(cam2);
console.log(test);
});
onvif.Discovery.probe({timeout:1000,resolve:false});
And in output in my example i've got 4 of these:
{ probeMatches:
{ probeMatch:
{ endpointReference: [Object],
types: 'tdn:NetworkVideoTransmitter',
scopes: ' onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/location/country/china onvif://www.onvif.org/type/network_video_transmitter onvif://www.onvif.org/hardware/IPC-122 onvif://www.onvif.org/Profile/Streaming onvif://www.onvif.org/name/IPC-BO',
XAddrs: 'http://192.168.1.81:10004/onvif/device_service',
metadataVersion: 1
}
}
}
And I want to keep only the XAddrs for all object generated and then put these in a json.
My first idea was to stringify this object then create a writable stream and put all json together but in this case there are no coma between the json so it doesn't create a big json with the whole data.
Thank you for your help
Jules
The easiest way to know how many addresses you have is the .length function of an array.
As I don't know whether you need a list with unique addresses or the same address can show up multiple times, I'm gonna show you both solutions.
Unique Addresses Only
function extract() {
test.forEach(cam => {
const deviceAddress = cam.probeMatches.probeMatch.XAddrs;
// only if the xaddrs is not in list yet, add it
if(test.filter(xad => xad === deviceAddress).length <= 0) {
xaddrs.push(cam.probeMatches.probeMatch.XAddrs);
}
});
// show the number of addresses
const listCount = xaddrs.length;
console.log('listCount: ', listCount);
}
No Unique Address
function extract() {
test.forEach(cam => {
xaddrs.push(cam.probeMatches.probeMatch.XAddrs);
});
// show the number of addresses
const listCount = xaddrs.length;
console.log('listCount: ', listCount);
}
Make testan array and push()the camobjects into it. Also define an array for your XAddrs-values.
var test = [];
var xaddrs = [];
// your other code
...
onvif.Discovery.on('device', function(cam,rinfo,xml){
// function will be called as soon as NVT responses
nombrecamera+=1;
console.log(cam);
// push cam object into array
test.push(cam);
cam2= JSON.stringify({cam}, null , ' ');
//console.log(cam2);
STREAM.write(cam2);
console.log(test);
});
Then extract XAddrs and push it into xaddrs array.
function extract() {
test.forEach(cam => {
xaddrs.push(cam.probeMatches.probeMatch.XAddrs);
});
// now you have an array containing only the XAddrs elements
console.log(xaddrs);
}

Firebase: Run a query synchronously

I am trying to set some user data depending on the no.of users already in my USERS COLLECTION. This even includes a userId which should be a number.
exports.setUserData = functions.firestore.document('/users/{documentId}')
.onCreate(event => {
return admin.firestore().collection('users')
.orderBy('userId', 'desc').limit(1)
.get().then(function(snapshot) {
const user = snapshot.docs[0].data();
var lastUserId = user.userId;
var userObject = {
userId: lastUserId + 1,... some other fields here
};
event.data.ref.set(userObject, {
merge: true
});
});
});
One issue I noticed here, quickly adding 2 users result in those documents having the same userId may be because the get() query is asynchronous?
Is there a way to make this whole setUserData method synchronous?
There is no way to make Cloud Functions run your function invocations sequentially. That would also be quite contrary to the serverless promise of auto-scaling to demands.
But in your case there's a much simpler, lower level primitive to get a sequential ID. You should store the last known user ID in the database and then use a transaction to read/update it.
var counterRef = admin.firestore().collection('counters').doc('userid');
return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data() || 0) + 1;
transaction.update(counterRef, newValue);
});
});
Solution
var counterRef = admin.firestore().collection('counters').doc('userId');
return admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data().value || 0) + 1;
transaction.update(counterRef, {
"value": newValue
});
});
}).then(t => {
admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var userIdCounter = counterDoc.data().value || 0;
var userObject = {
userId: userIdCounter
};
event.data.ref.set(userObject, {
merge: true
});
});
})
});

Filter Return of Meteor FindOne?

How would I go about filtering the return of a FindOne function in Iron Router? I assume that aggregation is out of the question, but I may be wrong. I've tried many different ways that don't work. I'd like to return the id, name, and the season object that it finds a matching season_number in.
My database is setup like so:
_id
name
seasons (array)
season (object)
season_number
episodes (array)
episode (object)
episode_title
episode_number
Here's my iron router code that is currently just running a findOne function.
Router.route('/show/:_id/season/:season_number', {
name: 'viewSeasonPage', // This links to the template
data: function() { return Tv.findOne({_id:"KQBXq4nri7zssDna2", "seasons.season_number": 2}))}
});
Router.route('/show/:_id/season/:season_number', {
name: 'viewSeasonPage', // This links to the template
data: function() {
let tv = Tv.findOne({_id:"KQBXq4nri7zssDna2", "seasons.season_number": 2});
if (tv && tv.seasons) { return tv.seasons.find(function(season) { return season.season_number == 2; })
}
});
You need to filter the result to create the data object you want to return with the information you need. If your search doesn't find anything, your data is an empty object.
Router.route('/show/:_id/season/:season_number', {
name: 'viewSeasonPage',
data: function() {
// Find your object
var tv = Tv.findOne({
_id: this.params._id,
seasons: {
$elemMatch: {
season_number: this.params.season_number
}
}
});
// Fill data by filtering the correct season
var data = {};
if (tv) {
data._id = tv._id; // 1. ID
data.name = tv.name; // 2. NAME
// Find correct season in array
var season;
for (var i = tv.seasons.length - 1; i >= 0; i--) {
season = tv.seasons[i];
if (season.season_number == this.params.season_number) {
data.season = season; // 3. SEASON
}
};
}
return data;
}
});
I know it's a lot of coding, but this is for understanding the idea and the process.

Detect differences between two objects (JSON)

I've got a remote JSON file that contains the list of the last 100 users who logged into a service. This JSON is updated constantly and lists the users from the most recently logged in to the "least recently" logged in.
If the user who appears as number X logs back in, they get removed from their position X and put back at the very top of the JSON at position [0].
I retrieve the JSON every 5 minutes. What I'd like to do is detect the differences between the old object oldUsers and the new newUsers and store them in another object that would only contain the users who are present in newUsers but not in oldUsers. I have no real idea as to how to achieve this.
Here's the JSON structure:
[{
"id":"foo09",
"name":"John",
"age":28
}, {
"id":"bar171",
"name":"Bryan",
"age":36
},
...
]
Is there a rather straightforward way to do it? Thanks!
You need to write your own diff algorithm. Here is one I whipped up in JSBin:
I will need a utility function to merge two arrays (Underscore would help here).
function mergeArrays(val1, val2) {
var results = val1.splice(0);
val2.forEach(function(val) {
if (val1.indexOf(val) < 0) {
results.push(val);
}
});
return results;
}
Diff algorithm
function diff(val1, val2) {
var results = [];
var origKeys = Object.keys(val1);
var newKeys = Object.keys(val2);
mergeArrays(origKeys, newKeys)
.forEach(function(key) {
if (val1[key] === val2[key]) { return; }
var result = {
key: key,
orig: val1[key],
'new': val2[key]
};
if (val1[key] == null) {
result.type = 'add';
} else if (val2[key] == null) {
result.type = 'delete';
} else {
result.type = 'change';
}
results.push(result);
});
return results;
}

Categories

Resources