JavaScript - recursive looping through object - javascript

I'm trying to make a simple ACL just for practice.
I want to loop through my object data and if my currentViewer has a parent I want to add his path (access in my object) to arrayAccess.
So if my viewer is user his accessArray should be ["", home], if he's admin it would be ["", home, user] and if he's a guest it will be only [""].
How to do it in a recursive way, so I don't have to create thousands of for loops?
I was trying calling a checkParent() inside my checkParent(), but it only makes my loop infinitive. I'm sorry if it's a silly question, I'm very beginning in JS.
var currentViewer = "user";
var data = {
users: [{
role: "guest",
access: ""
},
{
role: "user",
access: "home",
parent: "guest"
},
{
role: "admin",
access: "user",
parent: "user"
}
]
};
var accessArray = [];
function checkRole() {
var users = data.users;
for (var i = 0; i < users.length; i++) {
if (currentViewer === users[i].role) {
accessArray.push(users[i].access);
console.log(accessArray);
function checkParent() {
if (users[i].parent) {
for (var j = 0; j < users.length; j++) {
if (users[i].parent === users[j].role) {
accessArray.push(users[j].access);
console.log(accessArray);
}
}
}
};
checkParent();
}
};
};
checkRole();

You can try this:
var data = {
users : [
{ role:"guest" , access:"" },
{ role:"user" , access:"home", parent: "guest" },
{ role:"admin" , access:"user", parent: "user" }
]
};
var currentUser = "admin";
var arr = [];//array that you need
var defineAccess = function(item){
if(item.parent){
var index = data.users.map(function(e) { return e.role; }).indexOf(item.parent);
defineAccess(data.users[index]); //recursive calling
arr.push(data.users[index].access);
}
}
data.users.forEach(function(item){
if(currentUser === item.role){
arr.push(item.access);
defineAccess(item);
}
})
console.log(arr); //final output array

There are a bunch of ways to do it. Simple way is just make a hash for easy look up and reference the parents on a loop and push.
var data = { users : [
{ role:"guest" , access:"" },
{ role:"user" , access:"home", parent: "guest" },
{ role:"admin" , access:"user", parent: "user" }
]
};
var roleHash = data.users.reduce(function(o, i) {
o[i.role] = i;
return o;
}, {});
function getAccessRoles(roleKey) {
var role = roleHash[roleKey];
var roles = [role.access];
while (role.parent) {
role = roleHash[role.parent];
roles.unshift(role.access);
}
return roles;
}
console.log("admin", getAccessRoles("admin"));
console.log("user", getAccessRoles("user"));
console.log("guest", getAccessRoles("guest"));

I don't think "recursiveness" should be a goal on its own... Why not create a Map of roles and their properties and use the parent property to retrieve a new item from this map, until you can't?
var data = {
users: [{
role: "guest",
access: ""
},
{
role: "user",
access: "home",
parent: "guest"
},
{
role: "admin",
access: "user",
parent: "user"
}
]
};
var roles = new Map(data.users.map(u => [u.role, u]));
var getAccess = function(role) {
var access = [];
var current = roles.get(role);
while (current) {
access.push(current.access);
current = roles.get(current.parent);
}
return access.reverse();
}
console.log("guest", getAccess("guest"))
console.log("user", getAccess("user"))
console.log("admin", getAccess("admin"))

build an object model first,then the problem is simple.
var data = {
users: [
{
role: "guest",
access: ""
},
{
role: "user",
access: "home",
parent: "guest"
},
{
role: "admin",
access: "user",
parent: "user"
}
]
};
var users = data.users.reduce(function (roles, user) {
roles[user.role] = user;
return roles;
}, {});
var accessList = data.users.map(function (user) {
var all = [];
do {
all.unshift(user.access);
user = users[user.parent];
} while (user);
return all;
});
console.log(accessList);

Related

Group key value objects

I have an array of objects (pre_finalTab_new below) like this:
My goal is to group them by "schema", and then by "tip" and insert into new array, something like this:
var celotnaTabela = {};
for (var nov in pre_finalTab_new)
{
var shema = pre_finalTab_new[nov].schema.trim();
var objekt_tip = pre_finalTab_new[nov].type.trim();
var objekt_name = pre_finalTab_new[nov].name.trim();
var tip = pre_finalTab_new[nov].tip.trim();
if (celotnaTabela[shema] === undefined)
{
celotnaTabela[shema] = [];
if (celotnaTabela[shema][tip] === undefined)
{
celotnaTabela[shema][tip] = [];
if (celotnaTabela[shema][tip][objekt_tip] === undefined)
{
celotnaTabela[shema][tip][objekt_tip] = [];
celotnaTabela[shema][tip][objekt_tip] = [objekt_name];
} else
celotnaTabela[shema][tip][objekt_tip].push(objekt_name);
}
} else
{
if (celotnaTabela[shema][tip] === undefined)
{
celotnaTabela[shema][tip] = [];
}
if (celotnaTabela[shema][tip][objekt_tip] === undefined)
{
celotnaTabela[shema][tip][objekt_tip] = [];
celotnaTabela[shema][tip][objekt_tip] = [objekt_name];
} else
{
if (!celotnaTabela[shema][tip][objekt_tip].includes(objekt_name))
celotnaTabela[shema][tip][objekt_tip].push(objekt_name);
}
}
}
Then if i output celotnaTabela, i got this:
Expanded:
Even more:
But the problem is, when i try to use JSON.stringify(celotnaTabela), i got this:
{"HR":[],"ZOKI":[]}
But i need it to be in a right format, so i can pass this object into AJAX call..
Can anyone help me with this, what am i doing wrong?
i hope i understood everything right you asked for.
Next time provide the testdata and the wished result in textform pls.
var obj = [
{ schema: "HR", type: " PACKAGE", name: "PAKET1", tip: "new_objects" },
{ schema: "HR", type: " PACKAGE", name: "PAKET2", tip: "new_objects" },
{ schema: "HR", type: " PROCEDURE", name: "ADD_JOB_HISTORY", tip: "new_objects" },
{ schema: "ZOKI", type: " TABLE", name: "TABELA2", tip: "new_objects" },
{ schema: "ZOKI", type: " TABLE", name: "TABELA3", tip: "new_objects" },
];
var out = {};
for (var i = 0, v; v = obj[i]; i++) {
var a = v.schema.trim();
var b = v.type.trim();
var c = v.tip.trim();
var d = v.name.trim();
if (!out.hasOwnProperty(a)) {
out[a] = {};
}
if (!out[a].hasOwnProperty(b)) {
out[a][b] = {};
}
if (!out[a][b].hasOwnProperty(c)) {
out[a][b][c] = []
}
out[a][b][c].push(d);
}
console.log(JSON.stringify(out, null, 2));

Not able to add key value pair in a json object from a json object

I want to add key value pair to my json object from another json object.
I tried to read many stackoverflow similar questions but none of those solutions work in my case.
const oValues = {
action: "Open Browser & Login",
password: "something",
url: "https://***manage",
user: "user1",
}
var mElementsData = {
pages: [{
groups: [{
elements: [{}]
}]
}]
};
for (var key in oValues) {
if (oValues.hasOwnProperty(key)) {
mElementsData.pages.groups.elements["label"] = key;
mElementsData.pages.groups.elements["value"] = oValues[key];
}
}
console.log(mElementsData);
Your nested properties are not objects, but arrays of objects, so you cannot access them by dot notation. You can access them by index, here is an example:
const oValues = {
action: "Open Browser & Login",
password: "something",
url: "https://***manage",
user: "user1",
}
var mElementsData = {
pages: [{
groups: [{
elements: []
}]
}]
};
for (var key in oValues) {
if (oValues.hasOwnProperty(key)) {
const element = {
label: key,
value: oValues[key]
};
mElementsData.pages[0].groups[0].elements.push(element);
}
}
console.log(mElementsData);
Your pages, groups and elements elements are all arrays of objects, so you need to reference the specific array element ([0]) to set the value:
var mElementsData = {
pages: [{
groups: [{
elements: [{}]
}]
}]
};
var oValues = {
key: "value"
};
for (var key in oValues) {
if (oValues.hasOwnProperty(key)) {
mElementsData.pages[0].groups[0].elements[0]["label"] = key;
mElementsData.pages[0].groups[0].elements[0]["value"] = oValues[key];
}
}
console.log(mElementsData);
Pages and groups are array so you have to loop over and bind the object with key and value pair
var mElementsData = {
pages: [{
groups: [{
elements: [{}]
}]
}]
};
var oValues = {
action: "Open Browser & Login",
password: "something",
url: "https://***manage",
user: "user1",
}
for (var key in oValues) {
if (oValues.hasOwnProperty(key)) {
for (let i = 0; i < mElementsData.pages.length; i++) {
let pages = mElementsData.pages[i]
for (let j = 0; j < pages.groups.length; j++) {
pages.groups[j].elements[j][key] = oValues[key]
}
}
}
}
console.log(mElementsData)

Function variables as object field selector

I have the following function:
populateClinicRoomSelect(object) {
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key].id,
label: object[key].RoomName,
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
The idea is that takes two defined fields from the object array and places it in a new array. It works fine. I also have a few more functions exactly the same to this except the 'id' field and 'RoomName' field are different field names. Is there any way to pass 'id' and 'RoomName' as function variables to define them in the function?
Sure, you can pass field names as arguments and use [arg] accessors as you already do with [key]:
function populateClinicRoomSelect(object, valueField, labelField) {
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key][valueField],
label: object[key][labelField],
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
const object = {
a: {
id: 1,
room: 'first room'
},
b: {
id: 2,
room: 'second room'
}
}
const result = populateClinicRoomSelect(object, 'id', 'room');
console.log(result)
You mean like this?
function populateClinicRoomSelect(object, value, label) {
value = value || "id"; // defaults value to id
label = label || "RoomName"; // defaults label to RoomName
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key][value],
label: object[key][label],
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
let obj = { 1: { id:1, RoomName: "Blue Lounge" }, 2: { id:2, RoomName: "Red Lounge" } }
console.log(populateClinicRoomSelect(obj, 'id', 'RoomName'));

Merge objects with the same id in an array by adding their numeric properties

I already searched for a tutorial in Google but couldn't find what I needed.
I have an array like this:
[
{Username:'user1', Balance:'123'},
{Username:'user2', Balance:'213'},
{Username:'user1', Balance:'424'}
]
How to merge Balance when the Username is the same, for example merge Balance Username:'user1'
You can use a combination of higher-level built-in functions like Object.keys, Array#reduce, and Array#map to conditionally combine array entries when certain properties match.
var array = [{
Username: 'user1',
Balance: '123'
}, {
Username: 'user2',
Balance: '213'
}, {
Username: 'user1',
Balance: '424'
}]
var map = array.reduce(function (map, e) {
map[e.Username] = +e.Balance + (map[e.Username] || 0)
return map
}, {})
var result = Object.keys(map).map(function (k) {
return { Username: k, Balance: map[k] }
})
console.log(result)
Edit: OP requested that the answer be flexible enough to handle more than one property. I will leave my original snippet up as well, as in the end I think that one was more elegant.
var array = [{
Username: 'user1',
Balance: '123',
Another: '222'
}, {
Username: 'user2',
Balance: '213',
Another: '111'
}, {
Username: 'user1',
Balance: '424',
Another: '121'
}]
// Add elements to this array if you need to handle more properties
var properties = ['Balance', 'Another']
var map = array.reduce(function (map, e) {
map[e.Username] = properties.map(function (property, i) {
return +e[property] + ((map[e.Username] || [])[i] || 0)
})
return map
}, {})
var result = Object.keys(map).map(function (k) {
return map[k].reduce(function (object, e, i) {
object[properties[i]] = e
return object
}, { Username: k })
})
console.log(result)
You could use a single loop with a hash table for the reference to the objects with the same Username.
var data = [{ Username: 'user1', Balance: '123' }, { Username: 'user2', Balance: '213' }, { Username: 'user1', Balance: '424' }],
grouped = [];
data.forEach(function (hash) {
return function (o) {
if (!hash[o.Username]) {
hash[o.Username] = { Username: o.Username, Balance: 0 };
grouped.push(hash[o.Username]);
}
hash[o.Username].Balance += +o.Balance;
};
}(Object.create(null)));
console.log(grouped);
Here's one more solution, which I find a smidge less magicky than gyre's (but I'm also very interested by his.)
function mergeBalances(x) {
var users = [];
users = x.filter(function(entry) {
if(users[entry.Username]) { return false;}
users[entry.Username] = entry.Username;
return true;
})
.map(function(e) { return e.Username; } );
balances = {};
for(var i=0; i < users.length; i++) {
balances[i] = { Username:users[i]};
balances[i].Balance = x.filter(function(e) { return e.Username==users[i]; })
.reduce(function(total, e) { return total + eval(e.Balance);}, 0);
}
return balances;
}
// just call the function on your array
x = [ {Username:'user1', Balance:'123'}, {Username:'user2', Balance:'213'}, {Username:'user1', Balance:'424'} ]
console.log(mergeBalances(x));

javascript how to count the object and combin

I get the data from database like this:
var json = [
{
name: "one",
roles: [
{ role: "admin",state: 1 },
{ role: "operator",state: 1 },
{ role: "admin",state: 1 }
]
},
{
name: "two",
roles: [
{ role: "admin2",state: 0 },
{ role: "operator",state: 1 },
{ role: "admin",state: 1 }
]
}
];
And I want to become this
=>
var json = [
{
name: "one",
roles:[...],
data: [
{ "admin": 2,"eable": 2,"disable":0 },
{ "operator": 1,"eable": 1,"disable":0}
]
},
{
name: "two",
roles:[...],
data: [
{ "admin": 1,"eable": 0,"disable":1 },
{ "admin2": 1,"eable": 1,"disable":0},
{ "operator": 1,"eable": 1,"disable":0}
]
}
];
I'm getting stuck now, don't know what to do,please help.
Here is what I tried:
json.forEach(function(v,k){
var ret = {
"enable":0,
"disable":0
}
json[k]['data'] = [];
json[k]['roles'].forEach(function(v,k){
json[k]['data'].push( v['role'] );
})
});
http://jsfiddle.net/B9XkX/1/
This is a lot to chew on because the data structure is weird but bear with me:
result = json.map(function(obj){
// we can use map here to transform each object, whatever we return will
// go into the result array.
var roles = obj.roles.reduce(function(memo, item){
// we need to turn a role object into a data object
// but because we are counting the number of eable
// and disable states we need to make a discreet object
// that can hold the numbers without worrying about the
// final data structure.
memo[item.role] = memo[item.role] || {};
memo[item.role].eable = memo[item.role].eable || 0;
memo[item.role].disable = memo[item.role].disable || 0;
// we initialize the memo object if we haven't seen the
// role before.
if (item.state === 1) {
// we count eable for one state
memo[item.role].eable += 1;
} else if (item.state === 0) {
// we count disable for the other state
memo[item.role].disable += 1;
}
return memo;
}, {});
// now the roles object looks something like this:
/**
* {
* admin: {eable: 2, disable: 0},
* operator: {eable: 1, disable: 0}
* }
**/
return {
name: obj.name,
roles: obj.roles,
data: Object.keys(roles).map(function(key){
// now we need to turn the roles object back into an array, so we use
// Object.keys method to turn the keys on the roles object into an array
// and we use map again to setup an object that we will use instead.
var item = {};
item[key] = 1; // {admin: 1}
item.eable = roles[key].eable; // {admin:1, eable: 2}
item.disable = roles[key].disable; // {admin:1, eable: 2, disable: 0}
return item;
})
}
});

Categories

Resources