Spread operator not working in method map in Express.js - javascript

I get data from database using sequelize in Express.js query:
const users = await models.users.findAll({
deleted: 0,
});
Returned this:
[
{
"id": 1,
"name": "test",
"logo": "1588863296261.png",
}
]
Now I need add full adress to "logo":
http://127.0.0.1:3000/public/logo/1588863296261.png
So I using method map:
const dataUsers = users.map(user => ({
...user,
logo: user.logo ? `http://${req.headers.host}/public/logo/${user.logo}` : null,
}));
res.status(200).json(dataUsers);
dataUsers return null Object, but when I remove spread operator and I replace it with this:
id: user.id,
name: user.name,
description: user.description,
logo: user.logo ? `http://${req.headers.host}/public/logo/users/${user.logo}` : null,
Then it work correctly. Why spread operator does not work in this example ?

Related

Filtering an object by multiple arguments(inputs)

I have a lot of inputs, after which my object is supposed to filter, I can hardcode it, but there is probably a smarter way to do it
Filter state :
const [filters, setFilters] = useState<FiltersType>({
login: "",
name: "",
surrname: "",
});
Example data:
const data: UserRow[] = [
{
key: "1",
login: "John#gmail.com",
name: "John",
surrname: "Smith",
role: ["user"],
},
{
key: "2",
login: "Andrew#gmail.com",
name: "Andrew",
surrname: "Johnson",
role: ["user"],
},
];
data.filter((e) => {
if (
(!filters.name || e.name.includes(filters.name)) &&
(!filters.surrname || e.surrname.includes(filters.surrname)) &&
(!e.login ||
e.login.toLowerCase().includes(filters.login.toLowerCase()))
) {
return true;
}
return false;
})
For example, it can be done like this, but as you can see it looks bad and scales poorly when adding new fields, I tried to simplify it using "Object.entries()", but ultimately failed :(. What is the best pattern for such a problem?
You should use some() (logical OR for all the conditions) or every() (logical AND for all the conditions) in combination with filter().
const data = [
{
key: "1",
login: "John#gmail.com",
name: "John",
surrname: "Smith",
role: ["user"],
},
{
key: "2",
login: "Andrew#gmail.com",
name: "Andrew",
surrname: "Johnson",
role: ["user"],
},
];
const filter = {
login: "",
name: "",
surrname: "",
};
const filters = Object.entries(filter);
const filtered = data.filter((user) =>
filters.some(
([key, value]) =>
user[key] && user[key].toString().toLowerCase().includes(value)
)
);
console.log(filtered);
Use some() if you want to include the result if any of the filter conditions is met and use every() if you want to only include a result if all filter conditions are met.
The above will work for simple filters. You can however extend the solution using typeof() or Array.isArray() function etc. to process different types like arrays, nested objects etc. accordingly.

TypeError: can't define array index property past the end of an array with non-writable length

i am updating state in form by dynamically adding form fields but this error is coming up
what i have tried
what should happen is that more fields should be added to each subfields on click if i want
const addExperience = () => {
let temp = Object.assign({}, form);
temp.experience.push({
company: "",
position: "",
startDate: "",
endDate: "",
description: "",
});
setForm(temp);
}
this is the form
const [form, setForm] = useState({
name: "adarsh raj",
email: "adarsh#gmail.com",
phone: "83404dvsdsd",
address: "patel chowk",
city: "deoghar",
education: [
{
school: "dav ",
major: "intermediate",
GPA: "8.12",
},
],
experience: [
{
company: "venturepact llc",
position: "associate software developer",
startDate: "dd-mm-yyyy",
endDate: "dd-mm-yyyy",
description: "description",
},
],
projects: [
{
projectName: "project name",
projectDescription: "project description",
},
],
skills: [
{
skillName: "your skill name",
},
],
});
Object.assign(target, source) just Shallow copy.
useState return value is Immutable;
Refer to the following demo
var x = new Array(10).fill(0);
Object.freeze(x);
x.push(11) // same error
You can solve this problem by deep copying or reassigning the experience of the first layer.
Only the first layer can be assigned because a shallow copy is used. It cannot be resolved if the problem attribute appears at the second level. Therefore, this method is not recommended and deep copy is recommended.
let temp = JSON.parse(JSON.stringify(form));
let temp = lodash.cloneDeep(form);// need install lodash
code like this should work. But to test, you can try this syntax:
const addExperience = () => {
let temp = Object.assign({}, form);
temp.experience = [
...temp.experience,
{
company: "",
position: "",
startDate: "",
endDate: "",
description: ""
}
];
setForm(temp);
};
I solved now a similar problem creating a new array with spread operator like this
const newMutableArray = [...immutableArray, newItem]
it works fine for me.

Search object within object and get the key

I have an object router shown below. lets say I have another var x = "/podcast" and I want to find which key this variable x would reside. For example in this case I want to return the value "M2"
How can I search this object router and it's sub-objects to return the appropriate key?
Thanks!
var router = {
M1: {
url: "/",
description: "",
title: "",
image: "",
},
M2: {
url: "/podcast",
description: "",
title: "",
image: "",
},
M3: {
url: "/about",
description: "",
title: "",
image: "",
},
};
You can use Object.keys() to get Array of object keys then .filter(), here is a working snippet:
const search = '/podcast';
const router = {
M1: {
url: "/",
description: "",
title: "",
image: ""
},
M2: {
url: "/podcast",
description: "",
title: "",
image: ""
},
M3: {
url: "/about",
description: "",
title: "",
image: ""
}
};
const foundElement = Object.keys(router).filter((el) => router[el].url === search);
console.log(foundElement[0]);
To get your keys you use Object.keys(object)
To search the key you can use filter() or find().
To apply the condition you define callback function inside filteror find.
In my case, I used find function :
const foundElement = (router, searchableValue) => {
const founded = Object.keys(router).find(
(value) => router[value].url === searchableValue
);
return founded === undefined ? "Key not found" : founded;
};
const searchableValue = "/podcast";
console.log(foundElement(router, searchableValue));

How do I get information from one json object with the key of another json object?

I need to get the data from an array of json objects using the key of another array of json objects.
Specifically, what I need to do is get the name from the membership using the data stored in local storage (membershipSubscriptions.membership.id)
Basket Data
Data for the items in the basket - this is an array of objects from local storage
var basketContentsObject = jQuery.parseJSON(localStorage.getItem('localBasket'));
var membershipSubscriptions = basketContentsObject.data.membershipSubscriptions;
{
autoRenew: true
discount: 0
expiryDate: "2021-05-03T00:00:00"
id: "3807760AVVTBVCNPQVDKKCGMRBLGLCGRP"
isRenewal: false
membership: {
id: "7ALGBGVBCLVTGKNVNRTJPVKGBSPNGQPMK"
}
price: 47
startDate: "2020-05-04T00:00:00"
total: 47
}
Membership Data
json from the API that contains more information of this item - this id also an array of objects
$.getJSON( cache_url + "memberships.json", function(membership) {
console.log(ms);
});
{
"description": "Patrons - paying £250 annually",
"htmlDescription": "<div id>\r\n\t<h2>Patron £250 - Paying annually</h2>\r\n</div>",
"id": "7ALGBGVBCLVTGKNVNRTJPVKGBSPNGQPMK",
"imageUrl": "",
"name": "Patrons - £250 Yearly",
"thumbnailUrl": "",
"attribute_Type": "Patrons"
}
Here I am mapping the data from the api and join the keys from the object in local storage that has the same id as the current object from the api.
api.map((obj) => ({ ...obj, ...ls.find(({membership: {id}}) => id === obj.id)}))
There are two things you should look up if you don't know about them. Object Deconstruction and the Spread Operator. Next to that we have map and find that might be worth a look.
Here is a full working example:
const ls = [{
autoRenew: true,
discount: 0,
expiryDate: "2021-05-03T00:00:00",
id: "3807760AVVTBVCNPQVDKKCGMRBLGLCGRP",
isRenewal: false,
membership: {
id: "7ALGBGVBCLVTGKNVNRTJPVKGBSPNGQPMK",
},
price: 47,
startDate: "2020-05-04T00:00:00",
total: 47,
}]
const api = [{
attribute_Type: "Patrons",
description: "Patrons",
id: "7ALGBGVBCLVTGKNVNRTJPVKGBSPNGQPMK",
imageUrl: "",
name: "Patrons",
thumbnailUrl: "",
}]
console.log(
api.map((obj) => ({apiID: obj.id, ...obj,
...ls.find(({
membership: {id}
}) => id === obj.id)
}))
)
But you could also do it the other way around of course.
const ls = [{
autoRenew: true,
discount: 0,
expiryDate: "2021-05-03T00:00:00",
id: "3807760AVVTBVCNPQVDKKCGMRBLGLCGRP",
isRenewal: false,
membership: {
id: "7ALGBGVBCLVTGKNVNRTJPVKGBSPNGQPMK",
},
price: 47,
startDate: "2020-05-04T00:00:00",
total: 47,
}]
let api = [{
attribute_Type: "Patrons",
description: "Patrons",
id: "7ALGBGVBCLVTGKNVNRTJPVKGBSPNGQPMK",
imageUrl: "",
name: "Patrons",
thumbnailUrl: "",
}]
console.log(
ls.map((obj) => ({basketID: obj.id, ...obj,
...api.find(({
id
}) => id === obj.membership.id)
}))
)
You need to store the membership ID in a variable and then iterate through the membership data looking for a coincidence in the ID field.
It could look something like:
const member = "3807760AVVTBVCNPQVDKKCGMRBLGLCGRP";
const memberData = membershipData.find(item => item.id === member);
What this will do is iterate the Membership Data array of objects and, for each object in the array, check if the id property matches the member ID you are looking for. If a match is found, the entire object will be returned and will be accessible in the memberData variable. If no match is found, it will return null.
If there may be more than one coincidence and you need all of them, use filter instead of find, in which case memberData will be an array.
Hope this helps.

How to tidy my returning data into a better model

I have API data that isn't optimized in its structure
I cannot request backend devs restructure it, so I'm looking to tidy the model locally before use in my Angular 2 application.
As an example I receive a flat object which contains tables and user data
{$id: "400", sqlTable: "Customer", admin: 1, test: 3}
It would be best to filter these and place Users into a sub object to speed up rendering without conditional testing etc.
Preferred structure:
"sqlTable":"value",
"Users":[
"user1name":permission,
"user2name":permission
]
So from original data:
$id is unimportant (so was deleted)
sqlTable is the table name
admin and test are Users
So if we delete the $id, the "rule set" is anything that isn't sqlTable is a User and should be moved to Sub Object called Users.
It would be appreciated if anyone can provide example JS/TS on how to move the data (key/value) into the sub structure based on this ruleset.
Full returning data as requested:
{
"$id":"399",
"IsFailure":false,
"IsSuccess":true,
"Value":[
{
"$id":"400",
"sqlTable":"Customer",
"admin":1,
"test":null
},
{
"$id":"401",
"sqlTable":"CustomerAddress",
"admin":null,
"test":null
},
{
"$id":"402",
"sqlTable":"NewTable",
"admin":null,
"test":null
}
]
}
I would do some transformations to the data before rendering, something like this:
const data = {
$id: "399",
IsFailure: false,
IsSuccess: true,
Value: [
{
$id: "400",
sqlTable: "Customer",
admin: 1,
test: null
},
{
$id: "401",
sqlTable: "CustomerAddress",
admin: null,
test: null
},
{
$id: "402",
sqlTable: "NewTable",
admin: null,
test: null
}
]
};
//we map every value in "Values"
let result = data.Value.map(table => {
//first we create our users object, we copy the full object
let users = { ...table };
//then we delete extra keys that we do not want
delete users.sqlTable;
delete users.$id;
//then we build the object with the new structure
return { sqlTable: table.sqlTable, Users: users };
});
console.log(result);
Your original question asks for an array of users and your comments mention a need for the user object to have a name and permissions key, combining the two together, this transformation can be done in one statement like so,
const result = data.Value.map(value => ({
table: value.sqlTable,
users: Object.entries(value).filter(([key]) => key !== "$id" && key !== "sqlTable")
.map(([key, value]) => ({
name: key,
permissions: value
}))
}))
const data = {
$id: "399",
IsFailure: false,
IsSuccess: true,
Value: [{
$id: "400",
sqlTable: "Customer",
admin: 1,
test: null
},
{
$id: "401",
sqlTable: "CustomerAddress",
admin: null,
test: null
},
{
$id: "402",
sqlTable: "NewTable",
admin: null,
test: null
}
]
};
const result = data.Value.map(value => ({
table: value.sqlTable,
users: Object.entries(value).filter(([key]) => key !== "$id" && key !== "sqlTable")
.map(([key, value]) => ({
name: key,
permissions: value
}))
}))
console.log(result);

Categories

Resources