I try to implement a connection using relay and all the node's IDs are the same - reactjs

I write a really simple schema using graphql, but some how all the IDs in the edges are the same.
{
"data": {
"imageList": {
"id": "SW1hZ2VMaXN0Og==",
"images": {
"edges": [
{
"node": {
"id": "SW1hZ2U6",
"url": "1.jpg"
}
},
{
"node": {
"id": "SW1hZ2U6",
"url": "2.jpg"
}
},
{
"node": {
"id": "SW1hZ2U6",
"url": "3.jpg"
}
}
]
}
}
}
}
I posted the specific detail on github here's the link.

So, globalIdField expects your object to have a field named 'id'. It then takes the string you pass to globalIdField and adds a ':' and your object's id to create its globally unique id.
If you object doesn't have a field called exactly 'id', then it wont append it, and all your globalIdField will just be the string you pass in and ':'. So they wont be unique, they will all be the same.
There is a second parameter you can pass to globalIdField which is a function that gets your object and returns an id for globalIdField to use. So lets say your object's id field is actually called '_id' (thanks Mongo!). You would call globalIdField like so:
id: globalIdField('Image', image => image._id)
There you go. Unique IDs for Relay to enjoy.
Here is the link to the relevant source-code in graphql-relay-js: https://github.com/graphql/graphql-relay-js/blob/master/src/node/node.js#L110

paste the following code in browser console
atob('SW1hZ2U6')
you will find that the value of id is "Image:".
it means all id property of records fetched by (new MyImages()).getAll()
is null.
return union ids or I suggest you define images as GraphQLList
var ImageListType = new GraphQL.GraphQLObjectType({
name: 'ImageList',
description: 'A list of images',
fields: () => ({
id: Relay.globalIdField('ImageList'),
images: {
type: new GraphQLList(ImageType),
description: 'A collection of images',
args: Relay.connectionArgs,
resolve: (_, args) => Relay.connectionFromPromisedArray(
(new MyImages()).getAll(),
args
),
},
}),
interfaces: [nodeDefinition.nodeInterface],
});

Related

AWS Amplify The variables input contains a field name that is not defined for input object type

I have a series of forms that collects data into a form object, and on submit pushes that formdata to a dynamodb table via graphql query. For some reason I'm getting the following error.
The variables input contains a field name 'kidney infection' that is not defined for input object type 'CreateFormsInput'
I'm not sure what information is relevant to solving the issue, but here's my schema
type Forms #model #auth(rules: [{ allow: public }]) {
...
substances: [String]
medications: [AWSJSON]
condition_history: [AWSJSON]
allergies: [AWSJSON]
...
}
and here's how I'm pushing
const formResponse = await API.graphql(graphqlOperation(createForms, { input: tempForm }));
When I'm building the form, the condition_history value is an object, but i do stringify it because that's what aws wants. An example value would be a stringified {problem: "kidney infection"}, turned into "{\"problem\":\"kidney infection\"}". Of course, this is an array item, and multiple of these stringified objects can be in it.
And the thing is, I'm doing similar processes for things like medications and allergies but those aren't throwing any similar issues.
The issue does not persist if condition_history value is an empty array.
Am I missing something?
Edit to add more information.
The full(ish) createForm mutation autogenerated by graphql (adding ... to just cut out several irrelevant variables; just more of the same):
export const createForms = /* GraphQL */ `
mutation CreateForms(
$input: CreateFormsInput!
$condition: ModelFormsConditionInput
) {
createForms(input: $input, condition: $condition) {
id
facility_id
...
medications
condition_history
...
createdAt
updatedAt
}
}
`;
and the tempForm object that is sent to the API, also similarly trimmed to show relevant information:
{​
allergies: [ "{\"allergy\":\"\",\"details\":\"\"}" ],
...
condition_history: [ "{\"problem\":\"kidney infection\"}" ],
date_of_birth: "1966-01-04",
medications: [ "{\"medication\":\"\",\"dose\":\"\",\"frequency\":\"\"}" ]​,
smoking_history: "{\"has_smoked\":\"false\",\"currently_smokes\":\"\",\"cigarettes_per_day\":\"\",\"year_quit_smoking\":\"\"}",
}
and unstringified:
{
...
"smoking_history": {
"has_smoked": "false",
"currently_smokes": "",
"cigarettes_per_day": "",
"year_quit_smoking": ""
},
"medications": [
{
"medication": "",
"dose": "",
"frequency": ""
}
],
"allergies": [
{
"allergy": "blah",
"details": "sdsds"
}
],
"condition_history": [
{
"problem": "kidney infection"
}
],
"kidney infection": true #this might be the problem...
}

Adding an object to an array contained inside an object without overriding

I am currently trying to loop through an array of objects (each object is a task), where each task contains relevant information such as a name and date. Information from each task is then utilized in creating an object containing arrays, where each array contains objects that correspond to the date, or the array.
My current code is as follows:
contextTasks.forEach((taskItem) => {
taskItem["taskSchedule"].forEach((dateItem) => {
setItems((items) => ({
...items,
[dateItem["date"]]: [
{
name: taskItem["taskName"],
time: new Date(dateItem["time"]).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
}),
type: "Task",
},
],
}));
});
});
However, if there are multiple tasks with the same date, they will override each other and I only end up with one task per date. How would I go about pushing further objects to the array if there are other entries for that specific date?
Finished object:
Object {
"2021-04-21": Array [
Object {
"name": "Test Class v1",
"type": "Class",
},
],
"2021-04-24": Array [
Object {
"name": "Test Task v2",
"type": "Task",
},
//I would like to add another object here without overriding existing contents of the array
],
}
Have you tried using reduce ?
the idea will be to have something like this inside your accumulator:
{"date1": [{val}, {val}, ...] , "date2": [{val}, {val}, ...]}
array.reduce((acc, val) => {
// test if your accumulator has the same date as your date from the val
if(acc[val.date]) {
acc[val.date] = [... acc[val.date], ...your val]
} else {
// no date found in the accumulator so make acc.date = ...acc.date, val
acc[val.date] = [ val ]
}
}, {})
Sorry if the code is not perfect but if you want provide your initial array of data and I will fix the response code
The cause of your issue is the fact you're executing an async method inside a synchronous loop. Also, modifying state forces a re-render, and you're attempting to do it presumably many times at once. It might, and will cause a bottleneck at some point.
The solution: build your new state first, and execute a setState once.

Filter an Array through id and then mapping through a nested array inside

I'm stuck since a while trying to access a nested array inside another array after filtering it by an id. To be clear, this is the mock data I have:
bundleSets: [
{
id: 1,
title: "bundle set 1",
bundles: [
{
bundleTitle: "bundle 1",
content:[]
},
{
bundleTitle: "bundle 2",
content:[]
}
]
},
{ id:2,
title: "bundle set 2",
bundles: [
{bundleTitle: "ciaopao", content:[]}
]
},
{ id:3,
title: "bundle set 3",
bundles: [
{bundleTitle: "ciapo", content:[]}
]
}
]
Now I need to filter each bundleSets by id, and then access the bundles array inside and mapping those elements. This is what I tried to do:
const [key,setKey]=useState(1)
const [bundles,setBundles]=useState([])
useEffect(()=>{
const filteredBundles = bundleSets && bundleSets.filter(bundleSet=>bundleSet.id==key).map(filteredBundles=>{
return filteredBundles.bundles
})
setBundles(filteredBundles)
},[key])
Now If I try mapping the new state I can see on the console.log a weird [Array(1)] instead of the usual [{}] and I can't render it to the page. Where am I getting wrong with this?
Array.prototype.map returns an array and the callback you're passing to the map method returns filteredBundles.bundles which is an array. So, you get an array of arrays. filteredBundles is a confusing name, btw.
Since you're looking up the bundle by id and the ids are unique in the bundleSets array, you can use Array.prototype.find to find the bundle set by id and then get the bundle array. You can return an empty array if find returns undefined (if the key is not found).
const bundles = bundleSets?.find(set => set.id === key)?.bundles || []

multi path Array of objects mutation

Wanna mutate a path of array of Obj.
The object should change on-click and it looks like this:
<iron-icon id="id" icon="icons:arrow-downward" on-click="_sortTags"
class$="arrow [[sortData.id.icon]] [[sortData.id.state]]"></iron-icon>
Here i wanna mutate the sortData Obj, this function gets triggered on click on the above icon
_changeSortData(field,order,iconShape,status){ //there is a function calls this function but did not bring it here to make issue simple
this.set('sortData[field].sort', order);
this.set('sortData[field].icon', iconShape);
this.set('sortData[field].state', status);
}
The object below is the property:
sortData: {
type: Object,
value: function () {
return {
"id": {
"icon": "downward",
"sort": "default",
"state": "inactive"
},
"date": {
"icon": "downward",
"sort": "default",
"state": "inactive"
}
}
},
},
Now is it possible to escape single qoutes here in order to apply [field] as a pram
this.set('sortData[field].sort', order);
since there is tow fields in sortData Obj (id and data)
In this.set(path, value), path can be specified as a string or an Array. Since you have a dynamic path part, you would use an Array path like this:
this.set(['sortData', field, 'sort'], order); // `field` is dynamic
demo

Custom data unwrapping in ampersand.js model

I have a model - Configuration:
var Configuration = Model.extend({
props: {
name: 'string'
}
});
In the database, configuration model / table has 3 columns -> id, name and fields. The latter stores site config as a serialized array. When retrieving the entry from the database, I unserialize it and then pass it to the front end, so the front end receives this:
{
"id": 1,
"name": 'global',
"fields": {
"enabled": true,
"site_name": "Test"
}
};
What I want to do is to set whatever is inside fields object as properties on my model, or maybe session so that things get triggered throughout the site when they are updated. To visualize it, I want to achieve something like this:
var Configuration = Model.extend({
props: {
enabled: 'boolean',
site_name: 'string'
}
});
So basically, is there are a way to 'unwrap' stuff in fields object somehow?
The parse method is what you're looking for in this case. See https://github.com/AmpersandJS/ampersand-state/blob/master/ampersand-state.js#L93-L98 It allows you to transform incoming props.

Resources