Javascript combine object - javascript

I'm trying to transform the object received from the to a format used in backend.
I receive this object
{
'User.permissions.user.view.dashboard': true,
'Admin.permissions.user.view.dashboard': true,
'Admin.permissions.admin.view.dashboard': true,
}
The first part of the key (User, Admin) is the role name, the rest is the role. I need to combine this object into an object that has role names as keys for arrays containing the permission strings. The final result should look like this
{
'User': [
'permissions.user.view.dashboard'
],
'Admin': [
'permissions.user.view.dashboard',
'permissions.user.admin.dashboard;
]
}
So far I managed to get this result, but I'm not sure how to combine the results
const data = JSON.parse(req.body)
const permissions = Object.keys(data).map((key) => {
const permParts = key.split('.')
return {[permParts[0]]: permParts.slice(1).join('.')}
})
console.log(permissions);
[
{ User: 'permissions.user.view.dashboard' },
{ Admin: 'permissions.admin.view.dashboard' },
{ Admin: 'permissions.user.view.dashboard' }
]

const roleData = {
'User.permissions.user.view.dashboard': true,
'Admin.permissions.user.view.dashboard': true,
'Admin.permissions.admin.view.dashboard': true,
};
const mappedData = Object.keys(roleData).reduce((acc, entry) => {
const dotIndex = entry.indexOf('.');
const parts = [entry.slice(0,dotIndex), entry.slice(dotIndex+1)];
acc[parts[0]] ??= [];
acc[parts[0]].push(parts[1]);
return acc;
}, {});
console.log(mappedData);

You can use reduce function:
const result = permissions.reduce((acc, cur) => {
const key = Object.keys(cur)[0]
if (acc[key]) {
acc[key] = [...acc[key], cur[key]]
} else {
acc[key] = [cur[key]]
}
return acc
}, {})

Related

push object to an array within multiple loops

I have an array of objects like this [ { category: 'xxx' }, { author: '12345' } ]. My task is search this array and find in mongoDB to return _id [ { category: '_id' }, { author: '_id' } ]
I have code to do this, I create an empty array arrSearch and when it found the _id, it will push to this array. But after running, the array is empty, no data pushed. I'm not sure what wrong with it.
export const getObjIdFromCondition = async (conditionArr) => {
var arrSearch = []
try {
await conditionArr.map(obj => {
for (let key in obj) {
switch (key) {
case 'category':
const foundCategory = Category.findOne({ slug: obj[key] }).orFail()
foundCategory.then(resp => arrSearch.push({category: resp._id})) // push obj to array
break
case 'author':
const foundAuthor = Author.findOne({ author_id: obj[key] }).orFail()
foundAuthor.then(resp => arrSearch.push({ author: resp._id }))
break
default:
break
}
}
})
} catch (error) {
console.log(error);
}
console.log('arrSearch', arrSearch) // -> empty array
}
Can you help me? Thank you in advanced.
I try to use promise all and it works.
export const getObjIdFromCondition = async (conditionArr) => {
try {
var arrSearch = await Promise.all(
conditionArr.map(async (obj) => {
for (let key in obj) {
switch (key) {
case 'category':
const foundCategory = await Category.findOne({ slug: obj[key] })
return { category: foundCategory._id }
case 'author':
const foundAuthor = await Author.findOne({ author_id: obj[key] })
return { author: foundAuthor._id }
default:
break
}
}
})
)
} catch (error) {
console.log(error)
}
console.log("arrSearch", arrSearch)
}

Trying to access state in oncompleted method

I have API query and getting the result and setting those in a state variable in Oncompleted method of API query, Now i am updating the same state variable in another api query "onCompleted method.
I am not able to access the result from state what i have set before in first api query and below is my code
Query 1:
const designHubQueryOnCompleted = designHubProject => {
if (designHubProject) {
const {
name,
spaceTypes
} = designHubProject;
updateState(draft => { // setting state here
draft.projectName = name;
draft.spaceTypes = (spaceTypes || []).map(po => {
const obj = getTargetObject(po);
return {
id: po.id,
name: obj.name,
category: obj.librarySpaceTypeCategory?.name,
description: obj.description,
warning: null // trying to modify this variable result in another query
};
});
});
}
};
const { projectDataLoading, projectDataError } = useProjectDataQuery(
projectNumber,
DESIGNHUB_PROJECT_SPACE_TYPES_MIN,
({ designHubProjects }) => designHubQueryOnCompleted(designHubProjects[0])
);
Query 2:
const {
// data: designhubProjectSpaceTypeWarnings,
loading: designhubProjectSpaceTypeWarningsLoading,
error: designhubProjectSpaceTypeWarningsError
} = useQuery(DESIGNHUB_PROJECT_LINKED_SPACETYPE_WARNINGS, {
variables: {
where: {
projectNumber: { eq: projectNumber }
}
},
onCompleted: data => {
const projectSpaceTypeWarnings = data.designHubProjectLinkedSpaceTypeWarnings[0];
const warnings = projectSpaceTypeWarnings.spaceTypeWarnings.reduce((acc, item) => {
const spaceTypeIdWithWarningState = {
spaceTypeId: item.spaceTypeProjectObjectId,
isInWarningState: item.isInWarningState
};
acc.push(spaceTypeIdWithWarningState);
return acc;
}, []);
console.log(state.spaceTypes); // trying to access the state here but getting empty array
if (state.spaceTypes.length > 0) {
const updatedSpaceTypes = state.spaceTypes;
updatedSpaceTypes.forEach(item => {
const spaceTypeWarning = { ...item };
spaceTypeWarning.warning = warnings?.filter(
w => w.spaceTypeId === spaceTypeWarning.id
).isInWarningState;
return spaceTypeWarning;
});
updateState(draft => {
draft.spaceTypes = updatedSpaceTypes;
});
}
}
});
Could any one please let me know where I am doing wrong with above code Or any other approach to modify the state, Many thanks in advance!!

how to push the object keys and values to array

I need to push the key value pair to new array and should build the mongodb $match query.
const queryFormat = (payload) => {
delete payload.userEventId
var query = {}
var res = []
for(key in payload) {
if(typeof(payload[key])) {
res.push({ [key]: payload[key] })
}
else {
res.push({"$in" :{ [key]: payload[key] }})
}
}
console.log(res[3])
query['$match'] = {"$and" :res}
console.log(query)
}
const payload = {
id :1,
name : 'Alfred',
location : 'moon',
values : [{name: 'u',age:9}]
}
queryFormat(payload)
expected output
{"$match":{"$and":[{id:1},{name:"Alfred"},{location:"moon"},{"values":{"$in":[{name:"u"},{age: 9}]} }]}}
output I got
{"$match":{"$and":[{id:1},{name:"Alfred"},{location:"moon"},{"values":{"$in":[{name:"u",age: 9}]} }]}}
How to deal with it
Thanks!!
Currently you are specifying the key as "key"
Use [] to specify that you need the value of key as the key
const queryFormat = (payload) => {
delete payload.userEventId
var query = {}
var res = []
for(key in payload) {
res.push({ [key]: payload[key] })
}
query['$match'] = {"$and" :res}
console.log(query)
}
const payload = {
id :1,
name : 'Alfred',
location : 'moon'
}
queryFormat(payload)

How to turn array of objects in unique array?

This is my initial data:
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
]
I'm trying to turn an array of objects in unique array. This is my output:
const newData = {
amount: "1",
date: "2020-07-31T18:34:48.635Z",
shiftSelected: "10:00",
name: "Name",
surname:"aaa",
obs:"eee"
}
I can iterate over the array with a map call: let b = data.map(item => item.user), but I need to write more code to join then. I know that it's possible to do it with one unique logic. I tried but without successful.
You can use reduce with Object.assign to merge the properties of the objects. Note that with this method, later properties will overwrite previous ones.
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
];
const result = data.reduce((acc,{user})=>Object.assign(acc,user), {});
console.log(result);
Object spread syntax will also work.
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
];
const result = data.reduce((acc,{user})=>({...acc, ...user}), {});
console.log(result);
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
]
let b = data.reduce((acc, rec) => {
const { user } = rec
return { ...acc, ...user}
}, {} )
console.log(b)
use this after map over datas this is not a logic but.....
const x = data.map(obj => obj.user);
function flatObj(arr) {
const res = {};
arr.forEach(y => {
for(const key in y) {
res[key] = y[key];
}
})
return res;
}
const resault = flatObj(x);

Get object in array that contains closest matching id property in a string?

I am wondering if there is a better way to do get the result.
I have an array of objects, each object contains an id as a string path pattern. I want to return the object that has the best match to a url path. ATM I am using lodash
All id's are unique.
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/'
const sites = [{
'_id': '/la-nacion/economia'
}, {
'_id': '/la-nacion'
}, {
'_id': '/la-nacion/economia/finanzas'
}, {
'_id': '/la-nacion/economia/moodys'
}]
const urlArr = url.split('/')
const compare = sites.map(site => {
// get all matches
const siteArr = site._id.split('/')
// get lengths of matches
return _.intersection(siteArr, urlArr).length
})
// get index of obj with best match
const indexOfBestMatch = _.indexOf(compare, _.max(compare))
// new primary section
const newPrimarySection = sites.filter((e, i) => {
return i === indexOfBestMatch
})
console.log(newPrimarySection)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
https://jsbin.com/lumepereyi/1/edit?js,console
No need for a library, you can use reduce to iterate over the array of _ids, keeping a count of the number of substring matches, so that it resolves to the one with the most matches:
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/';
const sites = [{
'_id': '/la-nacion/economia'
}, {
'_id': '/la-nacion'
}, {
'_id': '/la-nacion/economia/finanzas'
}, {
'_id': '/la-nacion/economia/moodys'
}];
const substrings = new Set(url.split('/'));
const countMatches = str => str.split('/').reduce((a, substr) => a + (substrings.has(substr)), 0);
const { bestMatch } = sites.reduce(({ bestMatch, count=0 }, { _id }) => {
const thisCount = countMatches(_id);
return thisCount > count
? { count: thisCount, bestMatch: _id }
: { count, bestMatch };
}, {});
console.log(bestMatch);
Since you only need the item with the max matches, you can use _.maxBy() to iterate the array of sites, and extract the item. Use _.get() to extract the value of _id, because _.get() won't throw an error if sites is empty:
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/'
const sites = [{"_id":"/la-nacion/economia"},{"_id":"/la-nacion"},{"_id":"/la-nacion/economia/finanzas"},{"_id":"/la-nacion/economia/moodys"}]
const getPrimarySection = (url, sites) => {
const urlArr = url.split('/')
return _.get(_.maxBy(sites, site => {
const siteArr = site._id.split('/')
return _.intersection(siteArr, urlArr).length
}), '_id')
}
const newPrimarySection = getPrimarySection(url, sites)
console.log(newPrimarySection)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
If your path prefix is always the same (like it seems it is with /la-naction then you could do your own scoring (via startsWith) based on the length of the matched string and then sort-by desc (biggest score) ... and take the top score:
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/'
const sites = [{"_id":"/la-nacion/economia"},{"_id":"/la-nacion"},{"_id":"/la-nacion/economia/finanzas"},{"_id":"/la-nacion/economia/moodys"}]
const getBestMatch = (s, u, p = '/la-nacion') => { // <-- default prefix
const topScored = s.map(x =>
(Object.assign(x, {
score: ((`${p}${u}`).startsWith(x._id) ? x._id.length : 0)}), x)
).sort((a, b) => b.score - a.score)[0] // <-- sort, get the highest score
return topScored.score > 0 ? topScored._id : undefined
}
console.log(getBestMatch(sites, url))
No lodash neeed etc it is just map to add the score and then sort really.

Categories

Resources