Only add if not already in place - javascript

Here's my data structure:
var data = [
{ id: '1924', info: 'boo' },
{ id: '1967', info: 'foo' }
];
The id value should be unique, but the info may not be unique. How would I add new data into the data hash only if the id of the new data is unique?
Is the only way to iterate over the whole hash and see if there is such an id already in place?
data.push({ id: '1967', info: 'goo-goo' }); //should not be added
data.push({ id: '1963', info: 'goo-goo' }); //should be added

If you can change your data structure, it can be done with less code:
var data = {
'1924': {'info': 'goo-goo'},
'1967': {'info': 'boo-boo'}
};
function add(obj, id, data) {
if (obj[id] === undefined) { // if you have fear about the prototype chain being poisoned
// add in a hasOwnProperty
obj[id] = data;
}
}
This will also have the benefit of being a lot faster to access (if you have the ID).

Ivo, the problem with your solution is that I also keep track of the index of the info currently being displayed. The index of { id: '1967', info: 'foo' } would be 1 in that data hash, so I can reference it by data[1] if needed.

Related

Mapping data from two dictionary and make a resultant one with specific format in javascript

I have a two dictionaries:
featurePermissionMap = {'2':2,'3':1,'4':1} where key is the feature id and it's value represents the permission type.
Like '2':2 means for a feature id 2 we have a permission 2(Read and Write)
and '3':1 means for a feature id 3 we have a permission 1(Read-Only)
Second Dictionary:
feature_with_sub_feature =
[
{ name: 'FeatureA',
subfeatures: [
{ id: 2, name: 'Feature2' },
{ id: 3, name: 'Feature3' },
},
.......
];
I need a resultant dictionary like below:
read_write_access_feature = {
'read':{},
'write':{}
}
I just want to iterate over feature_with_sub_feature and based on subfeature id, I want output like
read_write_access_feature = {
'read':{'FeatureA':['Feature3',....],......},
'write':{'FeatureA':['Feature2',.....],....}
}
I am trying to achieve this using the two forEach. I am new to javascript.
Any optimized way would be much appreciated.
Any help/suggestions would be much appreciated.
Added function getFeatureWithPermission which will return features with permission passed in parameter. Added code explanation in comment.
call getFeatureWithPermission will required permission as below.
let read_write_access_feature = {
'read': getFeatureWithPermission(1),
'write': getFeatureWithPermission(2)
};
Try it below.
let featurePermissionMap = {'2': 2, '3': 1, '4': 1};
// return features with permission passed in parameter.
function getFeatureWithPermission(permission) {
// use reduce to update & return object as requiment
return feature_with_sub_feature.reduce((a, x) => {
// return object with key as x.name
// value as array of names from subfeatures which have respective permission
// first filter subfeatures for respective permission
// then use map to select only name from subfeatures
a[x.name] = x.subfeatures
.filter(y => featurePermissionMap[y.id] === permission)
.map(y => y.name);
return a;
}, {}); // <- pass empty object as input
}
let feature_with_sub_feature = [{
name: 'FeatureA',
subfeatures: [
{ id: 2, name: 'Feature2' },
{ id: 3, name: 'Feature3' },
]
}];
let read_write_access_feature = {
'read': getFeatureWithPermission(1),
'write': getFeatureWithPermission(2)
};
console.log(read_write_access_feature);

Return JSON Object by Value of a Key

I have a huge nested JSON object, and need to find a specific one by a certain value of a certain key.
For example:
[ {
id: 't53',
action: 'Boot',
time: 2019-04-21T17:58:34.579Z
},
{
id: 't54',
action: 'Reset',
time: 2019-04-24T17:57:33.549Z
} ]
So, if need to find the object where action is Boot, and the result must be:
{
id: 't54',
action: 'Boot',
time: 2019-04-24T17:57:33.549Z
}
You can use the Array.find method to get the first item that matches the condition.
const item = objs.find(obj => obj.action === 'Boot');
If you want to find the first element from last, you could create a shallow copy of the array and reverse it.
const item = objs.slice().reverse().find(obj => obj.action === 'Boot');
var data = [{
id: 't53',
action: 'Boot',
time: '2019-04-21T17:58:34.579Z'
},
{
id: 't54',
action: 'Boot',
time: '2019-04-24T17:57:33.549Z'
}];
var result = data.filter(a => a.action === 'Boot');
console.log(result);
You loop over the array and check each item action key is you want or not.

Firestore Update single item in an array field

I have a document in Firebase Firestore that is something like the below. The main point here is that I have an array called items with objects inside it:
{
name: 'Foo',
items: [
{
name: 'Bar',
meta: {
image: 'xyz.png',
description: 'hello world'
}
},
{
name: 'Rawr',
meta: {
image: 'abc.png',
description: 'hello tom'
}
}
]
}
I am trying to update a field inside the item array, under the meta object. For example items[0].meta.description from hello world to hello bar
Initially I attempted to do this:
const key = `items.${this.state.index}.meta.description`
const property = `hello bar`;
this.design.update({
[key]: property
})
.then(() => {
console.log("done")
})
.catch(function(error) {
message.error(error.message);
});
This didn't appear to work though, as it removed everything in the item index I wanted to modify, and just kept the description under the meta object
I am now trying the following which basically rewrites the whole meta object with the new data
const key = `items.${this.state.index}.meta`
const property = e.target.value;
let meta = this.state.meta;
meta[e.target.id] = property;
this.design.update({
[key]: meta
})
.then(() => {
this.setState({
[key]: meta
})
})
.catch(function(error) {
message.error(error.message);
});
Unfortunately though, this seems to turn my whole items array into an object that looks something like:
{
name: 'Foo',
items: {
0: {
name: 'Bar',
meta: {
image: 'xyz.png',
description: 'hello world'
}
},
1: {
name: 'Rawr',
meta: {
image: 'abc.png',
description: 'hello tom'
}
}
}
}
Any ideas how I can just update the content I want to?
Firestore doesn't have the ability to update an existing element in an indexed array. Your only array options for updates are described in the documentation - you can add a new element to the array ("arrayUnion") or remove an element ("arrayRemove").
As an alternative, you can read the entire array out of the document, make modifications to it in memory, then update the modified array field entirely.
You can make a separate collection for that particular array, like this in this picture earlier I had different fields (no collections) of name, email and pages, And in this, I wanted to change the data of a specific page that is inside the array. For that, I made a different collection of pages with individual documents of each page having values of title description and content which can be mutated.

underscore js - finding a nested object

I have an underscore filter which is returning the parent object which contains a child object I am looking for. But I want it to return just the child object. Since it is already doing the work of locating the child object in order to return the parent, I'm wondering how to simplify my code to return just the child. Here's the example:
var filterObj = _.filter(filtersPath, function(obj) {
return _.where(obj.filters, {id: prefilterCat}).length > 0;
});
So here, that nested object inside obj.filters, with the id of prefilterCat, is the object I want returned, not its parent. So currently I would have to do another find inside of filterObject to get what I need. Any ideas?
Underscore's filter method will return the "parent" object but will filter out the ones that don't match the conditional statement. That being the case, if there is only 1 result, then you can just access it similarly to how you would access an array. For instance:
var filterObj = _.filter(filtersPath, function(obj) {
return _.where(obj.filters, {id: prefilterCat}).length > 0;
})[0];
The above example would get the first child that is returned from the filter method.
From your question and code, I'm assuming a data structure like this:
var filtersPath = [
{
filters: [
{id: 0},
{id: 1}
]
},
{
filters: [
{id: 5},
{id: 42}
]
}
];
Now you can get an array of all "parent objects" (which you already have done) that have a filters array containing a object with matching ID:
_.filter(filtersPath, function(obj) {
return _.find(obj.filters, { id: 5 });
});
The advantage of doing it this way is that it will stop searching for a value once it's found one, and not always traverse the entire list.
If you want to actually get an array as result, it's a simple map operation:
_.chain(filtersPath)
.filter(function(obj) {
return _.find(obj.filters, { id: 5 });
})
.map(function(obj) {
return obj.filters;
})
.value();
If you only want to get the first matching object, you don't even need to use a filter or map:
_.find(filtersPath, function(obj) {
return _.find(obj.filters, { id: 5 });
})
.filters;
With lo-dash, this operation will be a little easier:
_.find(filtersPath, { filters: [{ id: 5 }] }).filters

prototype JSON to Object

The following is part of a JSON string returned from the server:
{
col1: {
caption: 'Workspace',
combodata: {
c_0: {
id: 0,
value: 'Filter...'
},
c_1: {
id: 1,
value: 'Tax'
},
c_2: {
id: 2,
value: 'HR'
}
}
}
}
After eval, I can access .caption, and .combodata is visible in Firebug as an object, with c_0 and c_1 visible as objects inside .combodata, with id and value in both c_0 and c_1.
How do I step through each object in .combodata? I tried .combodata.each(c), but that throws an exception. I won't know the names of the objects in .combodata during run time.
You can use a regular for loop for that:
for(var key in obj.col1.combodata) {
var combo_obj = obj.col1.combodata[key];
...
}
Can I suggest that you do not eval() the JSON that's returned? What you should be doing is:
var jsondata = { ... };
var obj = JSON.parse(jsondata);
The reason is because eval'ing a string can be dangerous. Imagine if your JSON data looked like this:
"{ some json data here }; alert(document.cookie)"
When you eval that, the users cookie is displayed to them. Now think what happens if instead of alert, that cookie is posted to an attackers URL. They now have access to that users account if such exists.
if
var result = {col1: { caption: 'Workspace',combodata: {c_0: {id: 0,value: 'Filter...'},c_1: {id: 1, value: 'Tax'},c_2: {id: 2, value: 'HR'}}}};
then
for ( i in result.col1.combodata ) {
var item = result.col1.combodata[i];
//Do stuff with item
}
I have found the following to work as well and will use this:
Object.values(col1.combodata).each(function(c2) {
id = c2.id;
});

Categories

Resources