JavaScript - specific queried from two databases - javascript

I need help with a JavaScript task.
How do I get something specific queried from two databases?
Task:
View the index.js file
Implement the gradeOverview() function, which gets the variables students and
grades and creates a grade overview for each student. Thereby
each element in the students array should be projected to an object in the following format:
{ student: (students[i]), grades: [(grades[j], grades[j+k], ...)] }
This is my function which accesses both databases and should retrieve and display a value from one database at a time based on the "student number".
function gradeOverview(students, grades) {
const result = students.map((student) => [
{
student: student,
grade: grades.reduce((grades, grade) => {
const student number = grade.studentnumber;
if (grades[matriculationnumber] == null) grades[matriculationnumber] = [];
grades[matriculationnumber].push(grade);
return grades;
}),
},
]);
console.log(result);
return result;
// TODO: implement me
}
The Data:
var students = [{
"matrikelnummer": 4636,
"vorname": "Vérane",
"nachname": "Voase"
}]
var grades = [{
"id": 628,
"matrikelnummer": 4636,
"grade": "3,3"
},
{
"id": 886,
"matrikelnummer": 4636,
"grade": "5,0"
}]
Output:
"student": {
"matrikelnummer": 4636,
"vorname": "Vérane",
"nachname": "Voase"
},
"grades": [
{
"id": 628,
"matrikelnummer": 4636,
"grade": "3,3"
},
{
"id": 886,
"matrikelnummer": 4636
"grade": "3,6"
}
]
},

Updated: Fiddle Link https://jsfiddle.net/uzrodex3/
I hope i guessed correctly your incoming data you put into gradeOverview function.
const studentsQueryResponse = [
{
name: "John Doe",
studentNumber: 123
},
{
name: "Johan Doe",
studentNumber: 321
},
{
name: "Jane Doe",
studentNumber: 111
}
]
const gradesQueryResponse = [
{
studentNumber: 123,
grade: 1
},
{
studentNumber: 123,
grade: 3
},
{
studentNumber: 321,
grade: 5
},
{
studentNumber: 123,
grade: 1
}
]
There is your function which returns in this case
[
{
"student": {
"name":"John Doe",
"studentNumber":123
},
"grade":[1,3,1]
},
{
"student": {
"name":"Johan Doe",
"studentNumber":321
},
"grade":[5]
},
{
"student": {
"name":"Jane Doe",
"studentNumber":111
},
"grade":[]
}
]
If you want to return whole grade object in array, then just remove map line which returns grade property value from grade object
function gradeOverview(students, grades) {
console.log("Input arguments", students, grades)
const results = students.map((student) => {
return {
student: student,
grade: grades
.filter((gradeObject) => gradeObject.studentNumber === student.studentNumber)
.map((gradeObject) => gradeObject.grade)
}
});
console.log("Results", results);
return results;
}
And then you call your function
gradeOverview(studenstQueryResponse, gradesQueryResponse)

Related

NaN after adding particular key element in an Array object

I have an Array object with 3000 objects. Among these 3000 few of them have grade and few object doesn't. Now I want to sum the grades. I'm getting NaN. Could you please guide me what am I doing wrong. Below is the sample code:
const arr=[
{
"name":"Harvey",
"grade":3
},
{
"name":"Pamela",
},
{
"name":"Scott",
"grade":4
},
{
"name":"Joshua",
"grade":5
},{
"name":"Rachel",
},{
"name":"Harvey",
"grade":3
},
]
let classTotal = arr.reduce(function (previousValue, currentValue) {
return {
grade: (previousValue.grade + currentValue.grade)
}
})
console.log(classTotal) //NaN
Also tried the following:
let classTotal=arr.reduce((accum, item) => accum + item.total, 0)
console.log(classTotal) // Same NaN
If either of the .grade values is itself not a number (such as undefined) then it will break the ongoing calculations. One approach could be to default it to 0 when no value is present. So instead of currentValue.grade you might use (currentValue.grade ?? 0). For example:
const arr=[
{
"name":"Harvey",
"grade":3
},
{
"name":"Pamela",
},
{
"name":"Scott",
"grade":4
},
{
"name":"Joshua",
"grade":5
},
{
"name":"Rachel",
},
{
"name":"Harvey",
"grade":3
},
];
let classTotal = arr.reduce(function (previousValue, currentValue) {
return {
grade: (previousValue.grade + (currentValue.grade ?? 0))
};
});
console.log(classTotal);
NaN is "Not a valid Number" you have some entries missing grade you should run filter to filter them out before your reduce
const arr = [{
"name": "Harvey",
"grade": 3
},
{
"name": "Pamela",
},
{
"name": "Scott",
"grade": 4
},
{
"name": "Joshua",
"grade": 5
}, {
"name": "Rachel",
}, {
"name": "Harvey",
"grade": 3
},
]
let classTotal = arr.filter(function(element) {
return element.grade
}).reduce(function(previousValue, currentValue) {
return {
grade: (previousValue.grade + currentValue.grade)
}
})
console.log(classTotal)
Or, you can add a 0 for example for the elements who does not have a grade:
const arr = [{
"name": "Harvey",
"grade": 3
},
{
"name": "Pamela",
},
{
"name": "Scott",
"grade": 4
},
{
"name": "Joshua",
"grade": 5
}, {
"name": "Rachel",
}, {
"name": "Harvey",
"grade": 3
},
]
let classTotal = arr.reduce(function(previousValue, currentValue) {
return {
grade: (previousValue.grade + (currentValue.grade || 0))
}
})
console.log(classTotal)

javascript optimize multiple reduce and map to extract data from nested objects

I am extracting some data out of an array of nested objects, using two reducees, and map, which is working at the moment, but it is a bit ugly. How can this be optimized?
function extractSchools(schools) {
let schoolData = [];
if (schools) {
schoolData = schools.reduce(function(parentdata, chlrn) {
let childrenlist = chlrn.children;
let childrendata = [];
if (childrenlist) {
childrendata = childrenlist.reduce(function(addrsslist, school) {
return addrsslist.concat(school.address.map(i => i.school));
}, []);
}
return parentdata.concat(chlrn.parent, childrendata);
}, []);
}
return {
schoolData
};
}
const schools = [{
"parent": "Thomas Jefferson",
"children": [{
"address": [{
"school": "School A"
}]
},
{
"address": [{
"school": "School B"
}]
}
]
},
{
"parent": "Jack Chan",
"children": [{
"address": [{
"school": "School C"
}]
}]
}
];
console.log(extractSchools(schools));
How can I optimize this function to get the same results? using one reduce instead of two... or some other optimal way of doing it.
You can remove the if (childrenlist) { and use a pre-filter.
function extractSchools(schools) {
let schoolData = [];
if (schools) {
schoolData = schools
.filter(data => data.children)
.reduce((parentdata, chlrn) => {
const childrendata = chlrn.children.reduce(
(addrsslist, school) =>
addrsslist.concat(school.address.map(i => i.school)),
[]
);
return parentdata.concat(chlrn.parent, childrendata);
}, []);
}
return { schoolData };
}
const schools = [
{
parent: "Thomas Jefferson",
children: [
{
address: [
{
school: "School A"
}
]
},
{
address: [
{
school: "School B"
}
]
}
]
},
{
parent: "Jack Chan",
children: [
{
address: [
{
school: "School C"
}
]
}
]
}
];
console.log(extractSchools(schools));
Try this, the result is little different than what you are expecting, but this will be a more generic way where you will have addresses with respect to school.
schools.map(p => {
return {[p.parent]: p.children.map(c => c.address.map(add => add.school))}
})
[
{
"Thomas Jefferson": [
[
"School A"
],
[
"School B"
]
]
},
{
"Jack Chan": [
[
"School C"
]
]
}
]

How to link nested json relationship values objects with lodash?

i'm trying to assign/merge (really don't know which lodash function) to nested json objects.
I have the following json structure:
{
"sports": [{
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}],
"competitions": [{
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sportId": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d"
}],
"contests": [{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competitionId": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe"
}]
}
I want to get one contest object with their relationship linked nested. The expected object is something like this:
{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competition": {
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sport": {
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}
}
}]
}
How can I get this kinda of relationship done using lodash ? It can be using pure javascript as well.
You don't need any special assignment operator, or lodash. You just use the =.
ogObject = {
"sports": [{
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}],
"competitions": [{
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sportId": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d"
}],
"contests": [{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competitionId": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe"
}]
};
newObject = ogObject.contests[0];
for(var i = 0; i<ogObject.competitions.length;i++){
if(ogObject.competitions[i].id == newObject.competitionId){
newObject.competition = ogObject.competitions[i];
for(var j = 0; j<ogObject.sports.length;j++){
if(ogObject.sports[j].id == newObject.competition.sportId){
newObject.competition.sport = ogObject.sports[j];
break;
}
}
break;
}
}
console.log(newObject)
This might be a builtin from lodash but I doubt it. It would require predefined knowledge of your schema vis-a-vis the relationship between sportId and sports, competitionId and competitions etc...
You really need to show us what you have tried so that we can advise you about the problems that you are facing, otherwise you are just asking for a code writing service ($).
However, in ES2016 you could do this.
'use strict';
const obj = {
sports: [{
id: 'c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d',
name: 'Soccer',
slug: 'soccer',
}],
competitions: [{
id: '4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe',
name: 'English Premier League',
sportId: 'c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d',
}],
contests: [{
id: '09cee598-7736-4941-b5f5-b26c9da113fc',
name: 'Super Domingo Ingles',
status: 'live',
competitionId: '4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe',
}],
};
const transformed = obj.contests.map((contest) => {
const competition = obj.competitions.find(item => item.id === contest.competitionId);
const sport = obj.sports.find(item => item.id === competition.sportId);
const sportLevel = { ...sport };
const competitionLevel = { ...competition, sport: sportLevel };
delete competitionLevel.sportId;
const contestLevel = { ...contest, competition: competitionLevel };
delete contestLevel.competitionId;
return contestLevel;
});
console.log(JSON.stringify(transformed, null, 2));
There's no built-in lodash function that can be used to flatten relational JSON structures. But something like this should work for you:
const sourceJSON = {
"sports": [{
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}],
"competitions": [{
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sportId": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d"
}],
"contests": [{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competitionId": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe"
}]
}
function findSport(source, sportId) {
let sport = _.find(source['sports'], {id: sportId});
if(!sport) {
return {};
}
return {
id: sport.id,
name: sport.name,
slug: sport.slug,
}
}
function findCompetition(source, competitionId) {
let competition = _.find(source['competitions'], {id: competitionId});
if(!competition) {
return {};
}
return {
id: competition.id,
name: competition.name,
sport: findSport(source, competition.sportId),
}
}
function flattenContests(source) {
return _.map(source['contests'], (contest) => {
return {
id: contest.id,
name: contest.name,
status: contest.status,
competition: findCompetition(source, contest.competitionId),
}
});
}
console.log(flattenContests(sourceJSON));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Note that considering your original JSON, the flattened object should likely be an array of contests (since contests itself is an array) instead of a single contest object that you're expecting.

Parse array of objects recursively and filter object based on id

i have this array of objects : getCategory (variable)
[
{
"id": "20584",
"name": "Produits de coiffure",
"subCategory": [
{
"id": "20590",
"name": "Coloration cheveux",
"subCategory": [
{
"id": "20591",
"name": "Avec ammoniaque"
},
{
"id": "20595",
"name": "Sans ammoniaque"
},
{
"id": "20596",
"name": "Soin cheveux colorés"
},
{
"id": "20597",
"name": "Protection"
},
{
"id": "20598",
"name": "Nuancier de couleurs"
}
]
},
{
"id": "20593",
"name": "Soins cheveux",
"subCategory": [
{
"id": "20594",
"name": "Shampooing"
},
{
"id": "20599",
"name": "Après-shampooing"
},
{
"id": "20600",
"name": "Masques"
},
and i tried everything i could search in stackoverflow ..
lets say on this array i want to get recursively and object with the specified id .. like 20596 and it should return
{
"id": "20596",
"name": "Soin cheveux colorés"
}
The logic way i am doing is like this :
var getSubcategory = getCategory.filter(function f(obj){
if ('subCategory' in obj) {
return obj.id == '20596' || obj.subCategory.filter(f);
}
else {
return obj.id == '20596';
}
});
dont know what else to do .
Thanks
PS : I dont use it in browser so i cannot use any library . Just serverside with no other library . find dont work so i can only use filter
You need to return the found object.
function find(array, id) {
var result;
array.some(function (object) {
if (object.id === id) {
return result = object;
}
if (object.subCategory) {
return result = find(object.subCategory, id);
}
});
return result;
}
var data = [{ id: "20584", name: "Produits de coiffure", subCategory: [{ id: "20590", name: "Coloration cheveux", subCategory: [{ id: "20591", name: "Avec ammoniaque" }, { id: "20595", name: "Sans ammoniaque" }, { id: "20596", name: "Soin cheveux colorés" }, { id: "20597", name: "Protection" }, { id: "20598", name: "Nuancier de couleurs" }] }, { id: "20593", name: "Soins cheveux", subCategory: [{ id: "20594", name: "Shampooing" }, { id: "20599", name: "Après-shampooing" }, { id: "20600", name: "Masques" }] }] }];
console.log(find(data, '20596'));
console.log(find(data, ''));

AngularJS Array Comparison

I have got the following array of Usernames
Usernames = [
{
"id": 1,
"userName": "Jack",
"description": "jack is a nice guy",
"userRoleIds": [
1
]
},
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
2,3
]
},
{
"id": 3,
"userName": "Smith",
"description": "Smithyyyy",
"userRoleIds": [
1,2
]
}
]
And an array of userRoles.
userRoles = [
{
id: 1,
roleName: "Admin"
},
{
id: 2,
roleName: "Tester"
},
{
id: 3,
roleName: "Developer"
}
]
What i want to get done is first concat the arrays in in Usernames and userRoles to get the following result.
Usernames = [
{
"id": 1,
"userName": "Jack",
"description": "jack is a nice guy",
"userRoleIds": [
{
"id": 1,
"roleName" : "Admin"
}
]
},
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
{
"id": 2,
"roleName" : "Tester"
},
{
"id": 3,
"roleName" : "Developer"
}
]
},...
The second thing i want is to be able to filter for the roleName and userName seperated by pipe signs. As in type something in a text box that searches for userName and roleName for example.
if i type
Caroline, Tester
The result will be
result = [
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
2,3
]
},
{
"id": 3,
"userName": "Smith",
"description": "Smithyyyy",
"userRoleIds": [
1,2
]
}
]
What is the best practice for achieving this?
Thanks
Here is how I would do it. I prefer using services and take advantage of their functions to keep code clean.
app.service('UserService', function (PermisionsServices) {
var self = {
'list': [],
'load': function (Users) {//Pass your array of Users
angular.forEach(Users, function (user) {
angular.forEach(user.userRoleIds, function (role) {
self.user.userRolesIds.push(PermisionsServices.get(role));
});
self.list.push(user);
});
}, 'get': function (id) {
for (var i = 0; i < self.list.length; i++) {
var obj = self.list[i];
if (obj.id == id) {
return obj;
}
}
}
};
return self;
});
app.service('PermisionsServices', function () {
var self = {
'list': [],
'load': function (permisions) {//Pass your array of permisions
angular.forEach(permisions, function (permision) {
self.list.push(permision);
});
}, 'get': function (id) {
for (var i = 0; i < self.list.length; i++) {
var obj = self.list[i];
if (obj.id == id) {
return obj;
}
}
}
};
return self;
});
Afterwards, you can use it on your controller:
$scope.users=UserService;
And access each of the users as a separate object which can have multiple object permisions.
NOTE: Building the service (populating it) will of course depend on your app logic and controller, you could just easily remove the "load" function and just hardcode the list object by copy and pasting your arrays.
This is the approach I use to load data from API via resource.
Regards
Edit:
For use on the UI, you would just call:
<div ng-repeat='user in users.list'>
{{user.name}} has {{user.permissions}}
</div>
as the object information is already contained within it.
Edit 2:
If you want to search your data, then you can just add a filter like this:
<div ng-repeat='user in users.list | filter: filterList'>
{{user.name}} has {{user.permissions}}
</div>
And then on the controller:
$scope.filterList = function (user) {
if ($scope.filterTextBox) {
return user.name.indexOf($scope.filterTextBox) == 0;
}
return true;
}
Hope this works for you
I would do with pure JS like this. It won't take more than a single assignment line each.
var Usernames = [
{
"id": 1,
"userName": "Jack",
"description": "jack is a nice guy",
"userRoleIds": [
1
]
},
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
2,3
]
},
{
"id": 3,
"userName": "Smith",
"description": "Smithyyyy",
"userRoleIds": [
1,2
]
}
],
userRoles = [
{
id: 1,
roleName: "Admin"
},
{
id: 2,
roleName: "Tester"
},
{
id: 3,
roleName: "Developer"
}
],
modified = Usernames.reduce((p,c) => (c.userRoleIds = c.userRoleIds.map(e => e = userRoles.find(f => f.id == e)),p.concat(c)),[]),
query = ["Caroline","Tester"],
filtered = modified.filter(f => query.includes(f.userName) || f.userRoleIds.some(e => query.includes(e.roleName)));
console.log(JSON.stringify(modified,null,2));
console.log(JSON.stringify(filtered,null,2));
You can use lodash to achieve this.
var role = _.find(userRoles, function(role) {
return role.roleName == 'Tester';
});
_.find(Usernames, function(user) {
return user.userName == 'Caroline' || _.indexOf(user.userRoleIds, role.id)>=0;
});

Categories

Resources