I am trying to make an input form where the user can change several values in one row simultaneously which get submitted to the database using the update() method. The values are being read from the Supabase Table into several input fields as defaultValues, which the user can edit and later submit form to update values in the Supabase instance of the table.
Input Form Looks Like This
The input values received from user are stored in a object that has the shape :
inputFields = {
"name": "Piramal Glassed", // NEW
"email": "piramal#glass.com", // NEW
"contact": "98203" // NEW
"pin": 400066,
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
}
The values marked as // NEW are the ones that have been changed by the user and need to be updated in the subsequent row in the Supabase Table.
I keep getting 400 Error. RLS is disabled for now. This is the function I am using to send the data back to the supabase table.
const { data, error } = await supabase
.from("company")
.update([inputFields.values])
.match([originalFields.values]); // Contains Original Values Of Row That Need To Be Replaced (same shape as inputFields.values)
};
What am I doing wrong here?
It looks like your match filter doesn't work.
I would suggest trying to match row by its ID since you want to update only one row. This way you are actually trying to update all rows that match this data, and that might be causing an issue. I am not sure if we can batch update like this with supabase at the moment.
This is something I'm using in my apps whenever I want to update data for a single row, and I don't have any issues with it. I would suggest to try this, if the question is still relevant. 😊
await supabase.from("company").update(inputFields).match({ id: company.id });
or
await supabase.from("company").update(inputFields).eq("id", company.id)
You could also pass only new values to .update() so you don't update whole row, but only data that has been changed.
Related
Based on the docs, inserting a new record
const { error } = await supabase
.from('countries')
.insert({ name: 'Denmark' })
returns
{
"status": 201,
"statusText": "Created"
}
For columns that are Is Identity, it automatically assigns a sequential unique number to the column.
How to get the ID of the newly inserted record on Supabase with JavaScript client?
You can add .select() after your insert statement in order to get the newly inserted record.
const { data, error } = await supabase
.from('countries')
.insert({ name: 'Denmark' })
.select()
You will see the inserted record inside data variable. Note that retrieving the inserted record requires you to have not only insert permission, but select permission on RLS policies.
On a side note, you can click on the buttons on the right of the docs to view different use cases. You can see this example on Create a record and return it example.
I have more than 50 fields those are input text and dropdowns in the reactive form. The fields are dependent to each other's value changes in order to trigger validation and to display related field after the selection.
I subscribed to the value changes in ngOnInit() as below:
ngOnInit() {
this.setPageValidation();
}
setPageValidation() {
this.NameSubscription = this.FormGroup.get('personnel').get('name').valueChanges.subscribe(data
=> {
this.enableOrders();
});
this.StateSubscription = this.FormGroup.get('personnel').get('state').valueChanges.subscribe(data
=>
{
this.enableAccount();
});
// more value changes subscription like 40 fields ............................
}
While loading the form, it is taking longer time to load due to subscribing for the value changes when the form loads.
I tried implementing it to move the code to ngOnChanges() but it is not triggering the enable and display of other fields depending on it's initial value that are filled from the table if there are values for those fields. It is just populating the first field and the rest does not display depending upon on its value.
I would like to thank you in advance. I really appreciate your help if there is any best approach to it to resolve without performance issue.
You can do with a single subscription.
this.personnelSubscription =
this.Formgroup.get('personnel').valueChanges.subscribe(data => {
if (data) {
//Console log the data here. It will print the formGroup of personnel
// then select the control and add your validations
// like this data.controls.state
}
})
I am using JSON Quickbase API documentation below:
Quickbase API
I am trying to update records with Quickbase via recordId as per below, and it's working fine:
{
"to": "my-table-id-goes-here",
"data": [
{
"6": {
"value": "nancy more is the value to be updated"
},
"3": {
"value": "recordId_to_be_used_to_make_updates"
}
}
]
}
My issue: I want to update where email and userid is equal to certain value.
Eg. in normal SQL queries something like "update mytable_name set name ='nancy more' where email='nancy#gmail.com' and userid=70".
Is it possible with Quickbase? Is there a way to achieve that based on the code above, assuming email field is 7 and userid field is 8 or whatever?
The end result is possible but not through a single API call. The insert/update records API call for Quick Base only updates records when the key field is included in the record payload (the key field is the record ID by default but can be changed to another field in the table). If you don't already know the value of the key field, you'll need to query for the matching records first and then use the returned record ID/key field to perform that update.
For example, you could query for records where email is "nancy#gmail.com" and userid is 70:
POST https://api.quickbase.com/v1/records/query
QB-Realm-Hostname: host
Authorization: QB-USER-TOKEN userToken
Content-Type: application/json
{
"from": "tableId",
"where": "{7.EX.'nancy#gmail.com'}AND{8.EX.70}"
}
You can then use the id's of the returned set of records to perform your update. How you go about reading the response and making the upsert request will depend on the language you're using.
According to the connection based model for pagination using graphQL, I have the following simplified schema.
type User {
id: ID!
name: String!
}
type UserConnection {
totalCount: Int
pageInfo: PageInfo
edges: [UserEdge]
}
type UserEdge {
cursor: String
node: User
}
type PageInfo {
lastCursor: Int
hasNextPage: Boolean
}
type Query {
users(first: Int, after: String): UserConnection
}
Consider the following router on within SPA front-end:
/users - once the user hit this page, I'm fetching first 10 records right up from the top of the list and further I'm able to paginate by reusing a cursor that I've retrieved from the first response.
/user/52 - here I'd like to show up 10 records that should go right from the position of user52.
Problem What are the possible ways to retrieve a particular subset of records on the very first request? On this moment I don't have any cursor to construct something similar to
query GetTenUsersAfter52 {
users(first: 10, after: "????") { # struggling to pass anything as a cursor...
edges {
node {
name
}
}
}
}
What I've already tried(a possible solution) is that I know that on a back-end the cursor is encoded value of an _id of the record in the DB. So, being on /users/52 I can make an individual request for that particular user, grab the value of id, then on the front-end I can compute a cursor and pass it to the back-end in the query above.
But in this case personally, I found a couple of disadvantages:
I'm exposing the way of how my cursor is computed to the front-end, which is bad since if I needed to change that procedure I need to change it on front-end and back-end...
I don't want to make another query field for an individual user simply because I need its id to pass to the users query field.
I don't want to make 2 API calls for that as well...
This is a good example of how Relay-style pagination can be limiting. You'll hit a similar scenario with create mutations, where manually adding a created object into the cache ends up screwing up your pagination because you won't have a cursor for the created object.
As long as you're not actually using Relay client-side, one solution is to just abandon using cursors altogether. You can keep your before and after fields, but instead simply accept the id (or _id or whatever PK) value instead of a cursor. This is what I ended up doing on a recent project and it simplified things significantly.
Right now, if I add a field to a Parse object and then save it, the new column shows up in the Parse dashboard.
For example, after running:
let media = new Parse.Object("Media");
media.set("foo", "bar");
await media.save();
I will have a new column called foo.
Is it possible to prevent this from happening?
Yes. This can be done using class-level permissions, which allow you to prevent fields being added to classes.
Parse lets you specify what operations are allowed per class. This lets you restrict the ways in which clients can access or modify your classes.
...
Add fields: Parse classes have schemas that are inferred when objects are created. While you’re developing your app, this is great, because you can add a new field to your object without having to make any changes on the backend. But once you ship your app, it’s very rare to need to add new fields to your classes automatically. You should pretty much always turn off this permission for all of your classes when you submit your app to the public.
You would have to add a beforeSave trigger for every one of your classes, keep a schema of all your keys, iterate over the request.object's keys, and see if there are any that do not belong in your schema. You can then either un-set them and call response.success(), or you can call response.error() to block the save entirely, preferably with a message indicating the offending field(s).
const approvedFields = ["field1", "field2", "field3"];
Parse.Cloud.beforeSave("MyClass", function(request, response) {
let object = request.object;
for( var key in object.dirtyKeys() ) {
if( approviedFields.indexOf(key) == -1 ) return response.error(`Error: Attempt to save invalid field: ${key});
}
response.success();
});
Edit:
Since this got a little attention, I thought I'd add that you can get the current schema of your class. From the docs: https://docs.parseplatform.org/js/guide/#schema
// create an instance to manage your class
const mySchema = new Parse.Schema('MyClass');
// gets the current schema data
mySchema.get();
It's not clear if that's async or not (you'll have to test yourself, feel free to comment update the answer once you know!)
However, once you have the schema, it has a fields property, which is an object. Check the link for what those look like.
You could validate an object by iterating over it's keys, and seeing if the schema.fields has that property:
Parse.Cloud.beforeSave('MyClass', (request, response) => {
let object = request.object;
for( var key in object.dirtyKeys() ) {
if( !schema.fields.hasOwnProperty(key) ) < Unset or return error >
}
response.success();
}
And an obligatory note for anyone just starting with Parse-Server on the latest version ,the request scheme has changed to no longer use a response object. You just return the result. So, keep that in mind.