How to update the value in action creator - react - reactjs

i am trying to update my response in the action creator.
Once then i receive response i am updating the time zone(as of now hardcoded)
Here the response
data = [
{
"created": {timestamp: "2018-05-12T16:55:32Z", Id: "234j", name: "jim"}
"id": "804690986026920900000061579629"
"lastUpdated": {timestamp: "2018-05-12T16:55:32Z", Id: "234j", name: "jim"}
"note": "standard 9"
},
{
"created": {timestamp: "2018-05-12T17:49:32Z", Id: "444a", name: "antony"}
"id": "804690986026920900000061579630"
"lastUpdated": {timestamp: "2020-05-12T16:49:32Z", Id: "444a", name: "antony"}
"note": "standard 9"
},
{
"created": {timestamp: "2018-05-12T17:55:12Z", Id: "123m", name: "mark"}
"id": "804690986026920900000061579631"
"lastUpdated": {timestamp: "2020-05-12T17:49:12Z", Id: "123m", name: "mark"}
"note": "standard 9"
}
];
action.js
then((results) => {
const hardcodedValue = "2020-05-22T04:49:44Z"
const getLocaltime = results.data.map((updatetime)=>{
return {...updatetime, lastUpdated.timestamp:hardcodedValue}
//getting error at lastUpdated.timestamp
})
results.data = getLocaltime;
dispatch({
type: "RECEIVED_DATA",
payload: updateId === '' ? {} : results,
})

Thats not a valid object:
{ ...updatetime, lastUpdated.timestamp:hardcodedValue }
Try fixing it to:
{ ...updatetime, lastUpdated: { ...updatetime.lastUpdated, timestamp: hardcodedValue } }
You could also do it like this:
updatetime.lastUpdated.timestamp = hardcodedValue;
return {...updatetime}
This would update the lastUpdated object and since you return a new outer object, the reference would change and you would not lose any data.

The easiest way, since its new data and the object reference can stay the same, you can just mutate it like this:
then((results) => {
const hardcodedValue = "2020-05-22T04:49:44Z";
results.data.forEach((row) => {
row.lastUpdated.timestamp = hardcodedValue;
});
dispatch({
type: "RECEIVED_DATA",
payload: localAccountId === '' ? {} : results,
})

Related

Please tell me how to resolve a type error

I'm writing a program that turns two data into a new one.
Each of the data comes from an API, so the undefined case must be considered.
but,
item.id === message.sender.userId
A type error occurs in userId in the section.
I want to resolve this type error.
I want to solve it by a means that does not change the type or data.
Is this possible?
const newMessages = React.useMemo(() => {
if (messages === undefined || userItems === undefined) return [];
return messages.map(message => {
if (message.sender.type === "user" && message.sender.userId) {
const user = userItems.find(item => item.id === message.sender.userId);
if (user) message.sender = { ...message.sender, icon: user.image };
}
return message;
});
}, [messages, userItems]);
Here are the two data I'm getting, and the type of one:
type IMessage = {
sender:
| {
type: "user";
userId: number;
}
| {
type: "admin";
adminId: number;
};
body:
| {
type: "text";
text: "text";
}
| {
type: "image";
text: string;
image: string;
};
};
const messages: IMessage[] =
[
{
"sender": {
"type": "admin",
"adminId": 789
},
"body": {
"type": "image",
"text": "abcde",
"image": "https://imageUrl"
},
},
{
"sender": {
"type": "user",
"userId": 10
},
"body": {
"type": "text",
"text": "Hello!"
},
},
{
"sender": {
"type": "user",
"userId": 13
},
"body": {
"type": "image",
"text": "Hello my friend!",
"image": "https://imageUrl"
},
},
]
const userItems =
[
{
"id": 10,
"name": "kenny",
"image": "https://imageUrl",
"age": 23,
"gender": "M",
},
{
"id": 13,
"name": "Jon",
"image": "https://imageUrl",
"age": 32,
"gender": "M",
}
]
const user = userItems.find(item => item.id === message.sender.userId);
You and i know that this function is going to be called right away, but typescript does not. In general, a callback function could be called at any time, synchronously or asynchronously, and nothing in the type information specifies that. As a result, typescript cannot guarantee that message.sender will still be a user when the callback gets called.
To fix this, assign the value to a const, so typescript can know for sure it won't change.
if (message.sender.type === "user" && message.sender.userId) {
const userId = message.sender.userId
const user = userItems.find(item => item.id === userId);
// ...
P.S:
body:
| {
type: "text";
text: "text";
}
You probably meant to do text: string

How to return id with Mongoose Aggregate Lookup with Apollo GraphQL

I have an aggregate function that returns people in a collection:
const getById = ({ id }) => {
return Project.aggregate([
{ $match: { _id: Types.ObjectId(id) } },
{
$lookup: {
from: "members",
localField: "_id",
foreignField: "project_id",
as: "members"
}
},
])
.then(data => {
const [project] = data;
console.log(project) // see below
return {
id: project._id,
...project
};
})
.catch(err => console.log(err));
}
If I return the data from this I get the following:
// Server response
{ _id: 5e2f57b577a8ce59c79e74af,
title: 'ok',
user_id: 5e2dc7961e6b840c315b5a03,
__v: 0,
members:
[ { _id: 5e447683b4f732cc9c4a9531,
name: 'Karl Taylor',
email: 'karl#queuey.dev',
project_id: 5e2f57b577a8ce59c79e74af,
position: 1,
__v: 0 },
{ _id: 5e45be128ed96a5eaef5d13e,
name: 'John Smith',
email: 'john#queuey.dev',
project_id: 5e2f57b577a8ce59c79e74af,
position: 2,
__v: 0 } ] }
However, when I query from the frontend using Apollo GraphQL, the id is null. (But it works on other items, as id is a getter for id but this does not happen on aggregate functions).
What is the best practice to map the id to the correct value? I would normally just use array.map but I feel like that might be overkill if I have too many members (at which point I would probably break this out to do pagination, but that's a different story.)
This is the response from frontend
// Client response
"project": {
"id": "5e2f57b577a8ce59c79e74af",
"title": "ok",
"members": [
{
"id": null, // <-- Notice here is null
"name": "Karl Taylor",
"email": "karl#queuey.dev",
"__typename": "Member"
},
{
"id": null, // <-- Notice here is null
"name": "John Smith",
"email": "john#queuey.dev",
"__typename": "Member"
}
],
"__typename": "Project"
}
This question here is similar, however, I do not believe it is a duplicate because we are querying different data. (the answer does not solve my question.)
I need to be able to return id otherwise cached redirects will not work.
I ran into this problem as well when I try to use aggregations.
simply you can you both ID's(id and _id) but it's not good thing.
what I use is to iterate the data
if the returning data of the query is not array use this
return {
...res._doc,
id: res._id,
}
but the returning data is an array you can add id to the response variable like below using forEach
res.forEach(element => {
element.id = element._id
});
return res;

Cannot log data from JSON-server API with GraphQL

I have built an API with JSON-server and I am trying to fetch the data from it using React-Apollo Client.
I'm trying to log the data from API on the console with Query tag, restructure and print the data variable using console.log().
I have no idea why the function is getting print via console.log().
I have the current setup:
JSON server is running on PORT 4000
Server is running on PORT 5000
Client is running on PORT 3000
I am already using CORS tool
Below is my component:
const BOOKS_QUERY = gql`
query BooksQuery {
books {
title
author
editionYear
}
}
`;
<Query query={BOOKS_QUERY}>
{({ loading, error, data }) => {
if (loading) return <h4>Loading...</h4>;
if (error) console.log(error);
console.log(data);
return <h1>test</h1>;
}}
</Query>
The content below is code for my schema:
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLInt },
title: { type: GraphQLString },
author: { type: GraphQLString },
editionYear: { type: GraphQLInt }
})
});
//Root Query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
books: {
type: new GraphQLList(BookType),
resolve(parent, args) {
return axios.get('http://localhost:4000/books').then((res) => res.data);
}
},
book: {
type: BookType,
args: {
id: { type: GraphQLInt }
},
resolve(parent, args) {
return axios.get(`http://localhost:4000/books/${args.id}`).then((res) => res.data);
}
}
}
});
module.exports = new GraphQLSchema({
query: RootQuery
});
API:
{
"books": [
{
"id": "1",
"title": "Java How To Program",
"author": "Deitel & Deitel",
"editionYear": "2007"
},
{
"id": "2",
"title": "Patterns of Enterprise Application Architecture",
"author": "Martin Fowler",
"editionYear": "2002"
},
{
"id": "3",
"title": "Head First Design Patterns",
"author": "Elisabeth Freeman",
"editionYear": "2004"
},
{
"id": "4",
"title": "Internet & World Wide Web: How to Program",
"author": "Deitel & Deitel",
"editionYear": "2007"
}
]
}
I only expect the API data to be logged on console.
Later I will render that data on screen.

React Axios Get Call to Output JSON Format

I am performing an Axios get call in a React Component to retrieve JSON info. That function is working great. Within the JSON is a label for various network ports, which are returning as an array in my axios call. These are ultimately going to be displayed as nodes on a d3 graph. My issue is that I need to output the data pulled from the get call into the following format:
nodes: [
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' }
]
So the full component for the graph to read is:
export const data = {
nodes: [
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' },
{ id: 'JSON data.label here' }
]
}
Here is the format of the Axios get I am using:
axios.get(`NetworkConstruct.json`)
.then(res => {
const names = res.data.items;
this.setState({ names });
});
Here is a sample output I am receiving (there are 11 of these):
{id: "5bc0860c-ece1-461c-bac0-b155a3cacd82", label: "80.107.0.212",
resourceTypeId: "tosca.resourceTypes.NetworkConstruct", productId:
"5bc0835c-6cfa-486e-8429-a59eaf4118bc", tenantId: "393fa8da-61fd-458c-80f9-
ce92d0ef0330", …}
The data has to be in this EXACT format or the graph won't read it. I'm guessing I'll need to do an initial map function but am stuck on how to arrange it. I cannot have any divs or quotes in my output. Is this doable? I have scoured the boards and Google for a couple of days and can't make this work yet.
Here is the object I am receiving from the GET request.
{
"id": "5bd2c6ef-6009-4b90-9156-62168f3c6293",
"resourceId": "5bd0ba82-2994-455d-8716-2adb5694d6f0",
"interface": "getGraph",
"inputs": {},
"outputs": {
"graph": {
"nodes": [
{
"id": "5bcdf06c-dd53-4335-840f-55a4b8d85a2d",
"name": "asw-lab9306b",
"ports": {
"GigabitEthernet3/0/8": "5bd1777f-0ab9-4552-962b-9e306ce378ab",
"GigabitEthernet2/0/15": "5bd1777e-119c-44e8-ba69-0d86a481c0f5",
"GigabitEthernet3/0/47": "5bd17783-be94-4aaf-8858-70e4eb3d02dc",
"GigabitEthernet2/0/13": "5bd17783-ed99-453f-a958-f764edaa8da8"
}
}
],
"links": [
{
"a": "5bd1a467-13f2-4294-a768-561187b278a8",
"z": "5bd17770-2e6c-4c37-93c8-44e3eb3db6dd",
"layer": "ETHERNET"
},
{
"a": "5bd1776e-c110-4086-87d6-a374ccee419a",
"z": "5bd17770-83ee-4e10-b5bb-19814f9f5dad",
"layer": "ETHERNET"
}
]
}
},
"state": "successful",
"reason": "",
"progress": [],
"providerData": {},
"createdAt": "2018-10-26T07:49:03.484Z",
"updatedAt": "2018-10-26T07:49:25.425Z",
"resourceStateConstraints": {},
"executionGroup": "lifecycle"
}
The info I need is the nodes ID. There are eleven of them in the full object.
You can map an array of objects to another array of objects in your format with Array.prototype.map(). Assuming that data is the list of objects from your response:
class Graph extends React.Component {
state = {
nodes: null,
};
componentDidMount() {
axios.get('the url').then(response => {
const nodes = response.data.outputs.graph.nodes;
this.setState({nodes});
});
}
render() {
const {nodes} = this.state;
if (!nodes) return 'Loading...'
return <TheD3ComponentYouUse nodes={nodes} />;
}
}

Mongoose Update array in a document does not work as expected

I'm scratching my head since a couple day on how to update the content of an array with Mongoose.
Here is my schema to begin with:
const playedGameSchema = new Schema ({
created: Date,
updated: Date,
game: {
type: Schema.Types.ObjectId,
ref: 'game'
},
creator: {
id: {
type: Schema.Types.ObjectId,
ref: 'user'
},
score: Number
},
partners: [{
id: {
type: Schema.Types.ObjectId,
ref: 'user'
},
score: Number
}]
});
module.exports = mongoose.model('PlayedGame', playedGameSchema);
Basically, what I want to achieve is to, at the same time:
- Update the creator.score (successful with dot notation).
- Update the score key for each partner (unsuccessful).
Here is the result of a document created:
{
"creator": {
"id": "5b8544fa11235d9f02a9b4f1",
"score": 0
},
"_id": "5bb6375f5f68cc5c52bc93ae",
"game": "5b45080bb1806be939bfde03",
"partners": [
{
"_id": "5bb637605f68cc5cafbc93b0",
"id": "5b85497111235d677ba9b4f2",
"score": 0
},
{
"_id": "5bb637605f68ccc70ebc93af",
"id": "5b85497111235d677ba9b4f2",
"score": 0
}
],
"created": "2018-10-04T15:53:03.386Z",
"updated": "2018-10-04T15:53:03.386Z",
"__v": 0
}
As I said, I was able to change the score of the score creator by passing something like { "creator.score": 500 } as a second parameter, then I switch to trying to update the array.
Here is my lambda function to update the score for each partner:
export const update: Handler = (event: APIGatewayEvent, context: Context, cb: Callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const body = JSON.parse(event.body);
let partnersScore: object = {};
if(body.update.partners) {
body.update.partners.forEach((score, index) => {
const key = `partners.${index}.$.score`;
partnersScore = Object.assign(partnersScore, { [key]: score});
console.log(partnersScore);
});
}
connectToDatabase().then(() => {
console.log('connected', partnersScore)
PlayedGame.findByIdAndUpdate(body.id, { $set: { partners: partnersScore } },{ new: true})
.then(game => cb(null, {
statusCode: 200,
headers: defaultResponseHeader,
body: JSON.stringify(game)
}))
.catch(err => {
cb(null, {
statusCode: err.statusCode || 500,
headers: { 'Content-Type': 'text/plain' },
body: err
})});
});
}
Which passes a nice { 'partners.0.$.score': 500, 'partners.1.$.score': 1000 } to the $set.
Unfortunately, the result to my request is a partners array that contains only one empty object.
{
"creator": {
"id": "5b8544fa11235d9f02a9b4f1",
"score": 0
},
"_id": "5bb6375f5f68cc5c52bc93ae",
"game": "5b45080bb1806be939bfde03",
"partners": [
{
"_id": "5bb63775f6d99b7b76443741"
}
],
"created": "2018-10-04T15:53:03.386Z",
"updated": "2018-10-04T15:53:03.386Z",
"__v": 0
}
Can anyone guide me into updating the creator score and all partners score at the same time?
My thoughs about findOneAndUpdate method on a model is that it's better because it doesn't require the data to be changed outside of the BDD, but wanting to update array keys and another key seems very difficult.
Instead, I relied on a set/save logic, like this:
PlayedGame.findById(body.id)
.then(game => {
game.set('creator.score', update.creatorScore);
update.partners.forEach((score, index) => game.set(`partners.${index}.score`, score));
game.save()
.then(result => {
cb(null, {
statusCode: 200,
headers: defaultResponseHeader,
body: JSON.stringify(result)
})
})
.catch(err => {
cb(null, {
statusCode: err.statusCode || 500,
headers: { 'Content-Type': 'text/plain' },
body: JSON.stringify({ 'Update failed: ': err })
})});
})

Resources