Get an object property name of a a nexted array - javascript

I'm pretty new to JavaScript and am wondering if I do it the correct way.
Consider this object:
const pageLinks = {
tickets: [
{ to: "/tickets/mytickets", },
{ to: "/tickets/newticket", },
{ to: "/tickets/followup", }
],
home: [
{ to: "/home/dashboard", }
],
about: [
{ to: "/about/author", }
]
}
When a user requests the route /tickets/followup I would like it to return tickets. This code, my first one ever, does exactly that:
const to = { path: '/tickets/followup' }
for (let page in pageLinks) {
let links = pageLinks[page]
links.forEach(element => {
if (element.to === to.path) {
console.log(page)
}
});
}
My question: is this the correct way of doing it? Or would it be better to use a filter() method?

Amusing each path has one destination page it would be faster to use the paths as keys and pages as values. This way lookup based upon path is simple and fast.
const pageLinks = {
tickets: [
{ to: "/tickets/mytickets", },
{ to: "/tickets/newticket", },
{ to: "/tickets/followup", }
],
home: [
{ to: "/home/dashboard", }
],
about: [
{ to: "/about/author", }
]
};
const routes = {};
for (const page in pageLinks) {
const links = pageLinks[page];
links.forEach(link => routes[link.to] = page);
}
console.log(routes);
const to = { path: '/tickets/followup' };
console.log(routes[to.path]);

In my opinion, the "correct way", or the "best way" of doing something is really relative. If your code solves the problem (and it does), it's fine. There are infinite ways of solving the same problem. Other two ways:
Using Object.keys and array.map:
const to = { path: '/tickets/followup' }
Object.keys(pageLinks).map(page => pageLinks[page].map(link => {
if (link.to == to.path) console.log(page)
}));
Using array.find:
const to = { path: '/tickets/followup' }
let found = Object.keys(pageLinks).find(page => pageLinks[page].find(link => link.to == to.path));
console.log(found);

Related

Is there a shorter way to write the below code?

I'm wondering if there is another shorter way to write the below code:
let playerListQuery = {
variables = {
input: {
pagination,
order: { field: PlayerOrderField.CreatedAtDesc },
where: {
// some others...
},
},
}
};
function updateSearch(value) {
if (!value) return;
playerListQuery.variables = {
...playerListQuery.variables,
input: {
...playerListQuery.variables.input,
where: {
...playerListQuery.variables.input.where,
or: [
{ nameContains: searchValue },
{
teamHas: [
{
or: [
{ nameContains: searchValue },
{ addressContains: searchValue },
],
},
],
},
],
},
},
};
}
As you can see I'm only interested to change the where field in updateSearch.
Is there a shorter way?
You could do a deep copy of your query then send the modified copy.
Something like so:
function updateSearch(value) {
if (!value) return;
const newQuery = deepCopy(playerListQuery);
newQuery.variables.input.where = { /* *** */ };
return newQuery;
}
As for the function that does the deep copy, if your JS object is serializable, JSON.parse(JSON.stringify(yourObject)) is a quick and easy way to deep copy
If you have more complex needs, you could look into libraries (e.g.: lodash's cloneDeep function).

Logic App/JavaScript - Remove Matching Values

I have two data sources. Data Source 1 is basically a list of Projects and Users assigned to those Projects. Data Source 2 is a list of Users that I want to remove from the Projects in Data Source 1.
Data Source 1:
[
{
"db1Project":[
{
"projectCode":"1",
"assignment":{
"db1User":[
{
"assignee":"wantzc"
},
{
"assignee":"michelles"
}
]
}
},
{
"projectCode":"2",
"assignment":{
"db1User":[
{
"assignee":"stallinga"
},
{
"assignee":"domanl"
},
{
"assignee":"brantleyd"
}
]
}
},
{
"projectCode":"3",
"assignment":{
"db1User":[
{
"assignee":"cinnamonk"
}
]
}
}
]
}
]
I want to match "assignee" from Data Source 1 with "sponsor" in Data Source 2.
Data Source 2:
[
{
"db2Users":[
{
"sponsor":"wantzc"
},
{
"sponsor":"patem"
},
{
"sponsor":"stallinga"
},
{
"sponsor":"oliviaa"
},
{
"sponsor":"brantleyd"
}
]
}
]
Then remove non-matching "assignee" and generate below output:
Desired Output:
[
{
"db1Project":[
{
"projectCode":"1",
"assignment":{
"db1User":[
{
"assignee":"wantzc"
}
]
}
},
{
"projectCode":"2",
"assignment":{
"db1User":[
{
"assignee":"stallinga"
},
{
"assignee":"brantleyd"
}
]
}
}
]
}
]
Can this be done using Logic App only? If not, how to do this using JavaScript?
This is a little bit of a verbose way to do it in Javascript, but the idea is relatively simple:
Create a map of the users you're looking for so you have an O(1) lookup instead of O(n) lookup each time
Filter the users list for each project to only contain users found in the db2Users list
Add the project to the new results set if any db1Users remain after step 2
This will take 1 pass through your original array, so it's an efficient, yet simple algorithm to do what you're trying to do.
let data = [{"projectCode":"1","assignment":{"db1User":[{"assignee":"wantzc"},{"assignee":"michelles"}]}},{"projectCode":"2","assignment":{"db1User":[{"assignee":"stallinga"},{"assignee":"domanl"},{"assignee":"brantleyd"}]}},{"projectCode":"3","assignment":{"db1User":[{"assignee":"cinnamonk"}]}}];
let db2Users = [{"sponsor":"wantzc"}, {"sponsor":"patem"}, {"sponsor":"stallinga"}, {"sponsor":"oliviaa"}, {"sponsor":"brantleyd"}];
let db2UsersMap = db2Users.reduce((res, curr) => {
res[curr.sponsor] = true;
return res;
}, {});
let filteredProjects = data.reduce((res, project) => {
let currProjUsers = project.assignment.db1User;
project.assignment.db1User = currProjUsers.filter((user) => db2UsersMap[user.assignee]);
if (project.assignment.db1User.length > 0) { res.push(project); }
return res;
}, []);
console.log(filteredProjects);

How to add dynamic elements to an object in typescript

I am sorry if I am asking a very basic question, I have done some research over the internet but not getting anything useful.
I have a typescript object like :
var productIds=["one","two","three"];
let searchfilter = {
or: [{
id: { match:productids['0'] }
},{
id: { match:productids['1'] }
},{
id: { match:productids['2'] }
}]
};
My productIds can be dynamic and may hold different counts of values.
How can I create the same structure for a dynamic number of values. I tried forEach, but not sure about the syntax.
productids.forEach(function(value){
// not sure if this is right syntax, I am not getting desired results.
searchfilter.or = { id: { match:value }};
});
Can you help me with it?
You can create your full or array with a simple .map() :
var productIds = ["1", "2", "3"];
let searchfilter = {
or : productIds.map( n => ({ id : { match : productIds[n] } }))
};
However Mongo (which I believe you are using) has a $match method that's made to match a list :
{
$match: {
productIds: {
$in: productIds
}
}
}
I'll keep it as simple as I can
var productIds=["one","two","three"];
let searchfilter = productIds.map(p => {
return {id: { match: p }};
});
// function
addNewProduct(id: string) {
this.searchfilter.push({id: { match: id }});
}

track path of recursive function

I'm trying to track path of a deep nested value in json object but having hard time getting the path. Each Item is an array of objects and can have child items. If the object c exists in the json data it is always located in the last item array.
item: [
{
a:5,
item: [
{
item: [
{c:1},
{x:4},
],
...
},
{},
{}
]
},
{},
{}
]
const findPath = (items) => {
let path = []
items.forEach((item,i) => {
if('item' in item){
path = path.concat(findPath(item.item))
}
else if('c' in item) {
path.push(i)
}
})
return path
}
if I have 3 c objects with different item depths, then I would have:
[
[0,0,0], //item[0].item[0].item[0].c
[1,0], //item[1].item[0].c
[4]] , //item[4].c
Any help?
Your main problem here is that you don't track the common case. You store the index only when you found a leaf, but you want all the steps in between. This being recursion, you also have to carry your return values with you, or you end up stepping on them. This works:
objects = [
{},
{
item: [
{},
{},
{
a:5,
item: [
{
item: [
{c:1},
{x:4},
]
},
{},
{}
]
},
{}
]
}
]
const findPath = (items, current_path, matching_paths) => {
items.forEach((item,i) => {
if('item' in item){
current_path.push(i);
current_path = current_path.concat(
findPath(item.item, current_path, matching_paths)
);
}
else if('c' in item) {
current_path.push(i);
matching_paths.push( current_path.slice() );
current_path = [];
}
})
}
var path = [];
var paths = [];
findPath(objects, path, paths);
console.log(paths); //[[1, 2, 0, 0]]
If C is found push a path object to the path array and update that path object for the rest of the paths.
const findPath = (items) => {
let path = []
items.forEach((item,i) => {
if('item' in item){
let item_path = findPath(item.item)
if(item_path.length > 0){
item_path[0].path.push(i)
path.push(item_path[0])
}
}
else if('c' in item){
path.push({path:[i], c:item.c})
}
})
return path
}
The function must be recursive, which means it should call itself with different parameters and not loop forever.
Below is what you are looking for. I made it in TypeScript to make sure I typed it correctly, but just take off all type definitions and it becomes JavaScript:
const trackPath: number[][] = [];
function findPath(topItem: any, path: number[], position: number): void
{
const currentPath = path.slice();
currentPath.push(position);
const newTopItem = topItem['item'];
if (Array.isArray(newTopItem)) {
// here is the recursion for each subitem
newTopItem.forEach((item, i) => findPath(item, currentPath, i));
}
if ('c' in topItem) {
trackPath.push(currentPath);
}
}
// this is the main method to call
function actuallyGetThePath(myTopItem: any): number[][] {
findPath(myTopItem, [], 0);
return trackPath;
}
Good luck!

normalizr v3 and JSON api

I want to normalise the responses I receive from an API. A typical response could look something like this:
// Get all projects
{data:[
{
id: 1
...
team:{
data: {
id:15
...
}
}
},
{
id:2,
....
},
{
id:3,
...
}
]}
How do I write my schemas so that it removes the 'data' container?
Currently, my schema looks like:
export const project = new schema.Entity('projects', {
team: team, // team omitted
},
{
processStrategy: (value, parent, key) => parent.data
}
)
export const arrayOfProjects = new schema.Array(project)
And I am using it like:
const normalizedProjects = normalize(jsonResponse, arrayOfProjects)
normalizedProjects then looks like this:
{
entities:{
projects:{
undefined:{
0:{
team:{
data:{
id:15,
...
}
}
},
1:{...},
2:{...}.
...
50:{...},
}
}
},
result:[] // length is 0
}
I'm not sure why the list of projects is contained in 'undefined', either?
I also use json_api schema.
How about like this?
const projectsSchema = new schema.Entity('projects', {}, {
processStrategy: processStrategy
});
export const processStrategy = (value, parent, key) => {
const attr = value.attributes;
delete value.attributes;
return { ...value, ...attr };
};
export const fetchProjectsSchema = {
data: [projectsSchema]
}
Each of your entity schema that you want to have the data omitted (or anything else fundamentalyl changed) needs to include a processStrategy that you write to remove or change any data. (see more examples in the tests)

Categories

Resources