how to check value exist in object of array - javascript

var aclData=[
{
'Manage Users':
['add','view','edit','delete']
},
{
'Manage Role':
['add','view','edit']
}
];
How to check 'view' exist in 'Manage Role'

This should do the trick:
for (var i = 0; i<aclData["Manage Users"].length; i++){
if(aclData["Manage Users"][i] == "view"){
// exists
}
}
Edit: Assumend you hava a dictonary. E.G:
var dict = []; // create an empty array
var dict = [];
aclData.push({
key: "Manage Users",
value: ...
});

Related

how to populate tree from flatTreeNode?

I have treeFlatNode array i want to structure it in tree format. or can i display this array in tree directly in angular.
data=[
{
expandable: true
level: 0
name: "2021-12-31"
path: null
},
{
expandable: false
level: 2
name: "A.txt"
path: "2021-12-31/B/C/A.txt"
}
]
required format
tree=[
name:"2021-12-03",
children:[
name:"B",
children:[{
name:"C"
children:[{
name:"A.txt"
children:[]
}]
}]
]
]
You could use an object (map) that maps a (sub)path to a node in the final tree. If it doesn't exist yet, it is added to the parent's children.
As your tree structure actually represents a forest (there can be multiple roots), I would name the result variable forest instead of tree
Snippet:
function toForest(data) {
const roots = [];
const map = {};
for (const obj of data) {
let key = "";
let children = roots;
for (const name of (obj.path ?? obj.name).split("/")) {
let child = map[key += "/" + name];
if (!child) children.push(map[key] = child = { name, children: [] });
({children} = child);
}
}
return roots;
}
// Example run
let data = [{expandable: true,level: 0,name: "2021-12-31",path: null}, {expandable: false,level: 2,name: "A.txt",path: "2021-12-31/B/C/A.txt"}];
let forest = toForest(data);
console.log(forest);
So, to transform your data structure to the desired one, you can use following function (with comments =) ):
transform(data){
const tree = [];
for (let node of data) {
// If there's no path it's a parent node
// but add it only if it doesn't exist yet
if (node.path === null && tree.every(n => n.name !== node.name)) {
tree.push({ name: node.name, children: [] });
continue;
}
// Extract name of parent node and other nodes
const [parentNodeName, ...pathElems]: string[] = node.path.split('/');
// Look-up for the parent node
let parentNode = tree.find(t => t.name === parentNodeName);
// If parent doesn't exist yet, so we create it here
if (!parentNode) {
parentNode = { name: parentNodeName, children: [] }
}
let children = parentNode.children;
// If the level of the node is relevant
// otherwise simply iterate over all pathElems
for(let i = 0; i <= node.level; i ++) {
let child = children.find(c => c.name === pathElems[i]);
// If the child doesn't exist yet - create it
if (!child) {
child = {
name: pathElems[i],
children: []
}
children.push(child);
children = child.children;
continue;
}
// Child does exist, so use it's children for the next iteration
children = child.children;
}
}
return tree;
}
And you can call this function, for example, in ngOnInit:
ngOnInit() {
this.tree = this.transform(this.data);
}
I do not use Angular, but if you just need to convert your flat to nested:
var data = [
{
expandable: true,
level: 0,
name: "2021-12-31",
path: null
},
{
expandable: false,
level: 2,
name: "A.txt",
path: "2021-12-31/B/C/A.txt"
}
]
var to_nested = function(flat) {
var nested = []
var cache = {}
var l = flat.length
var cache_assert = function(name) {
if (cache[name] == null) {
cache[name] = {
name: name,
children: []
}
}
}
for (var i = 0; i < l; i++) {
var current_node = flat[i]
cache_assert(current_node.name)
if (current_node.path == null) {
nested.push(cache[current_node.name])
} else {
var names = current_node.path.split("/")
var parent_name = names.shift()
cache_assert(parent_name)
names.forEach(function(name) {
cache_assert(name)
cache[parent_name].children.push(cache[name])
parent_name = name
})
}
}
return nested
}
var a = to_nested(data)
console.log('a: ', a)
console.log('a: ', a[0].children)
console.log('a: ', a[0].children[0].children)
And if you want to return to flat:
var level = 0
var cache = []; cache[level] = a.slice(0)
var parent = []; parent[level] = null
var index = []; index[level] = 0
while (level >= 0) {
var node = cache[level][index[level]]
if (node != null) {
console.log('node: ', node)
if (
node['children'] != null &&
Object.prototype.toString.call(node['children']) === '[object Array]' &&
node['children'].length
) {
level++
index[level] = 0
parent[level] = Object.assign({}, node)
delete parent[level]['children']
cache[level] = node['children'].slice(0)
} else {
index[level]++
}
} else {
parent[level] = null
level--
index[level]++
}
}

How to create single array for same key but different values

How to create single array for same key but different values in nodeJs with unique productId
but having different productImage with same productId i want productImage should be an array
and with same productId, productImages are in this productImage array.
var data = [
{
"productID":18,
"productTitle":"Watch",
"productImage":"1588148225540.jpg"
},
{
"productID":18,
"productTitle":"Watch",
"productImage":"15881482433232.jpg"
},
{
"productID":19,
"productTitle":"Shirt",
"productImage":"1588148214343.jpg"
}
]
My expected output should be:
[
{
"productID":18,
"productTitle":"Watch",
"productImage":[
"1588148225540.jpg",
"15881482433232.jpg"
]
},
{
"productID":19,
"productTitle":"Shirt",
"productImage":[
"1588148214343.jpg"
]
}
]
You can use uniqBy function from lodash library
const result = _.uniqBy(products, 'productID');
Here is an answer
var data = [
{
"productID":18,
"productTitle":"Watch",
"productImage":"1588148225540.jpg"
},
{
"productID":18,
"productTitle":"Watch",
"productImage":"15881482433232.jpg"
},
{
"productID":19,
"productTitle":"Shirt",
"productImage":"1588148214343.jpg"
}
]
let output =[];
data.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.productID == item.productID;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
output[existingIndex].productImage =
output[existingIndex].productImage.concat(item.productImage);
} else {
if (typeof item.productImage == 'string')
item.productImage = item.productImage;
item.productThumbImage = [item.productThumbImage];
output.push(item);
}
});

Recursively find keys on an object

I have a javascript object structured like this;
brand: {
group: {
subGroup: {
items: []
},
otherSub: {
items: []
}
}
}
Given an array of keys ['brand', 'group', 'newGroup', 'newSubGroup'] I want to split the keys into found and missing keys. So for the structure above I should get back;
present = ['brand', 'group']
missing = ['newGroup', 'newSubGroup']
I'm using ES6 and have lodash available, but struggling to find a clean way to produce this.
This is not to just check existence, it's recursively find the keys and return those present and the remaining ones.
Here's a pretty sketchy way that works.
const find = (keys, obj) => {
const string = JSON.stringify(obj);
return keys.reduce(({ present, missing }, key) => {
const match = string.match(new RegExp(`"${key}":`));
if (match) {
present.push(key);
} else {
missing.push(key);
}
return { present, missing };
}, { present: [], missing: [] });
}
You can use this function made for you ;)
var getAttrs = function(obj) {
return [].concat.apply([], Object.keys(obj).map(function (key) {
var results = [key]
if (typeof obj[key] === 'object') {
Array.prototype.push.apply(results, getAttrs(obj[key]))
}
return results
}))
}
It return the list of properties and children properties.
getAttrs({brand: {
group: {
subGroup: {
items: []
},
otherSub: {
items: []
}
}
}})
> ["brand", "group", "subGroup", "items", "otherSub", "items"]
And you can use it like so:
var lookingFor = ['brand', 'group', 'newGroup', 'newSubGroup']
var existings = getAttrs(obj)
var missings = []
var presents = []
lookingFor.forEach(attr => {
if (existings.indexOf(attr) === -1) {
missings.push(attr)
} else {
presents.push(attr)
}
})
I wrote a function to recursively get unique keys from a nested object, then filtered the array of all the keys you mentioned checking which were present in the result of my function.
var thisObject = {
brand: {
group: {
subGroup: {
items: []
},
otherSub: {
items: []
}
}
}
};
var arr_full = ['brand', 'group', 'newGroup', 'newSubGroup'] ;
var key_array = [];
function addToKeyArray( key_array, object ){
for( var key in object ){
// only get unique keys
if( key_array.indexOf( key ) === -1 ){
key_array.push( key );
}
// concat the result of calling this function recurrsively on object[key]
key_array.concat( addToKeyArray( key_array, object[key] ) );
}
return key_array;
}
var test = addToKeyArray( [], thisObject );
var missing = arr_full.filter( function( el ) {
return test.indexOf( el ) < 0;
});
console.log( test );
console.log( missing )
You can create recursive function using for...in loop inside another function and return object as result..
var obj = {"brand":{"group":{"subGroup":{"items":[]},"otherSub":{"items":[]}}}}
var keys = ['brand', 'group', 'newGroup', 'newSubGroup'] ;
function findKeys(data, keys) {
keys = keys.slice();
function findPresent(data, keys) {
var result = []
for(var i in data) {
if(typeof data[i] == 'object') result.push(...findPresent(data[i], keys))
var index = keys.indexOf(i);
if(index != -1) result.push(...keys.splice(index, 1))
}
return result
}
return {present: findPresent(data, keys), missing: keys}
}
console.log(findKeys(obj, keys))
To keep things clean and readable you can use "for in", inside a nested function for your recursion.
function recur(obj) {
let preMiss = {
present: [],
missing: []
}
let root = traverse => {
for (let key in traverse) {
if (Array.isArray(traverse[key].items)) {
preMiss.missing.push(key);
}
if (typeof traverse[key] === 'object' && !Array.isArray(traverse[key].items)) {
preMiss.present.push(key);
root(traverse[key])
}
}
}
root(obj);
return preMiss;
}
const object = {
brand: {
group: {
subGroup: {
items: []
},
otherSub: {
items: []
}
}
}
}
console.log(Object.entries(recur(object)));
var toFind = ['brand', 'group', 'newGroup', 'newSubGroup'],
found = [];
var o = {
brand: {
group: {
subGroup: {
items: []
},
otherSub: {
items: []
}
}
}
}
//called with every property and its value
function process(key,value) {
var i = toFind.indexOf(key);
if(i !== -1){
found.push(key);
toFind.splice(i, 1);
}
}
function traverse(o,func) {
if(!toFind.length) return;
for (var i in o) {
func.apply(this,[i,o[i]]);
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
traverse(o[i],func);
}
}
}
traverse(o,process);
console.log(found); // present
console.log(toFind); // absent
Traverse method taken from https://stackoverflow.com/a/722732/1335165
Even though this question is a bit older, I want to present a rather short solution to the problem.
const recursivelyGetKeys = obj => Object.keys(obj).map(key => typeof obj[key] === 'object'
? [...recursivelyGetKeys(obj[key]), key] : [key]).reduce((p, c) => [...p, ...c], [])
This function will return all keys in the object, so a call to the array arr with
const arr = {
brand: {
group: {
subGroup: {
items: []
},
otherSub: {
items: []
}
}
}
}
will output:
const keys = recursivelyGetKeys(arr) // = ["items", "subGroup", "items", "otherSub", "group", "brand"]
Now to find the intersection set of this and find = ['brand', 'group', 'newGroup', 'newSubGroup'], do:
const found = keys.filter(key => find.some(val === key))
const missing = keys.filter(key => find.every(val !== key))

How can I separate certain object keys into their own array?

This is my first question on here. Doesn't appear to be asked elsewhere, but then again I'm not sure exactly how to phrase my question.
How can I transform an array that looks like this:
var message = {
pay_key: '12345',
'transaction[0].sender_id': 'abc',
'transaction[0].is_primary_receiver': 'false',
'transaction[0].id': 'def',
'transaction[1].sender_id': 'xyz',
'transaction[1].is_primary_receiver': 'false',
'transaction[1].id': 'tuv',
};
into something like this:
{
pay_key : '12345',
transaction : [
{
sender_id : 'abc',
is_primary_receiver : 'false',
id : 'def'
},
{
sender_id : 'xyz',
is_primary_receiver : 'false',
id : 'tuv'
}
]
}
I have no control over the format of the first object as it comes from an external service. I am trying to insert the message object into a MongoDB collection, but when I try to do an insert as-is, I get an error. So I'm trying to put it into the correct form.
Should I be using Underscore for this? I've played around with _.each but can't get it to work.
my take..
var message = {
pay_key: '12345',
'transaction[0].sender_id': 'abc',
'transaction[0].is_primary_receiver': 'false',
'transaction[0].id': 'def',
'transaction[1].sender_id': 'xyz',
'transaction[1].is_primary_receiver': 'false',
'transaction[1].id': 'tuv',
};
message.transaction=[];
for (var p in message) {
var m = p.match(/^transaction\[(\d+)\]\.(.*)/);
if (m&&m[1]&&m[2]) {
message.transaction[m[1]]=message.transaction[m[1]]||{};
message.transaction[m[1]][m[2]]=message[p];
delete message[p];
}
}
Here's a generic function I just whipped up
function makeObject(message) {
var retObj = {},
makePath = function (p, pos) {
if (/\[\d+\]$/.test(p)) {
var q = p.split(/[\[\]]/),
r = q[0],
s = q[1];
if (!pos[r]) {
pos[r] = [];
}
return pos[r][s] = pos[r][s] || {};
}
return pos[p] = pos[p] || {};
};
for(var k in message) {
if (message.hasOwnProperty(k)) {
if (k.indexOf('.') < 0) {
retObj[k] = message[k];
}
else {
var path = k.split('.'),
pos = retObj,
last = path.pop();
path.forEach(function(p) {
pos = makePath(p, pos);
});
pos[last] = message[k];
}
}
}
return retObj;
}
It works as required, but I'm sure there's some better code to do it
Had a similar response, so adding it anyway:
Object.keys(message).forEach(function(key) {
var keySplit = key.split( /\[|\]\./g )
if ( keySplit.length != 1 ) {
if ( !message.hasOwnProperty(keySplit[0]) )
message[keySplit[0]] = [];
message[keySplit[0]][keySplit[1]] = message[keySplit[0]][keySplit[1]]||{};
message[keySplit[0]][keySplit[1]][keySplit[2]] = message[key];
delete message[key];
}
});

Update backbone.js model with new array element

I have a backbone.js model similar to the one shown below.
Filters = Backbone.Model.extend({
defaults : {
title: [ ["title1", "easy"], ["title2", "hard"] ]
}
});
I'm trying to add an element to the first-level array, such that the model then becomes:
Filters = Backbone.Model.extend({
defaults : {
title: [ ["title1", "easy"], ["title2", "hard"], ["title3", "medium"] ]
}
});
The code I have right now is this:
function setFilters() {
var options = {};
for (var facet in facets) {
for (var facetKey in facets[facet]) {
if (!filterExists(facetKey)) {
options[facetKey] = new Array(new Array(facets[facet][facetKey], "equals"));
}
else {
(filters[facetKey]).push(new Array(facets[facet][facetKey], "equals"));
}
}
}
filters.set(options);
}
The function filterExists simply checks if the key "title" is present in the model. When I run this, it says that filters[facetKey] is undefined. But isn't this the first-level array I need to push my element into?
You can access model attributes with .get() and .set() functions, or directly via the .attributes property:
http://documentcloud.github.com/backbone/#Model-attributes
var filters = new Filters();
filters.attributes.facetKey.push( [...] );
OR
filters.set('facetKey', ( filters.get('facetKey') || []).concat([...]));
Anyway, here is your transformed function which may or may not work:
function setFilters() {
for (var facet in facets) {
for (var facetKey in facets[facet]) {
var f = [ facets[facet][facetKey], "equals" ];
if( filterExists(facetKey)) {
// OR: if( filters.attributes[ facetKey ]){
filters.attributes[ facetKey ].push( f );
}else{
filters.attributes[ facetKey ] = [ f ];
}
}
}
// trigger change event for all attributes
filters.set( filters.attributes );
}
Bonus:
(filters.attributes[ facetKey ] = filters.attributes[ facetKey ] || [] ).push(f);

Categories