Database not including result from aggregated fields done with afterInsert webhook.

Sorry for newbie question, I am just trying out Velo for the first time.

My Goal:
I have a form with two fields: lastName and firstName. I would simply like to have another column, fullName that contains lastName and firstName pasted together.

Collection Settings:

  • Permissions set to Anyone can view, edit, update and Admin can delete

  • Draft & Publish Items is off.

Here’s what I have done:

  1. Added new column to mycollection called fullName

  2. Wrote the following code in data.js

export function mycollection_afterInsert(item, context) {
    let hookContext = context;
    item.fullName = `${item.firstName} ${item.lastName}`;
    console.log(item.fullName);
    return item;
}

Here’s what has happened:

  1. Log message works. When I use firstName = “John” and lastName =“Smith”, the log returns message: [“John Smith”] as expected. (see snippet at end of this post for JSON of log)

  2. In my database, in the fullName column, there is nothing there. firstName and lastName are both there.

  3. I have tried this with and without context. I have read all the articles about web hooks but clearly I just don’t understand something.

Here’s what I don’t understand

  1. Why function works for log but does not get added to collection?

  2. What is context used for? I copied this code, but I don’t understand where hookContext is used or why it is needed. Does the problem have to do with this?

  3. Does issue have to do with my collection settings?

Thanks!

Log:

"root":{"insertId":"..........ID"
"timestamp":"2022-10-06T20:33:34.067Z"

"labels":{"siteUrl":"n/a"
"revision":"508"
"namespace":"Velo"
"tenantId":"ID"
"viewMode":"Site"
}

"sourceLocation":{"file":"backend/data.js"
"line":3
"column":12
}

"operation":{"id":"ID"
"producer":"backend"
}

"jsonPayload":{"message":"["John Smith"]"
}
"receiveTimestamp":"2022-10-06T20:33:34.130Z"
}

  1. Why function works for log but does not get added to collection?

You already recognized, that it is a → AFTER-INSERT -HOOK ?
You are trying to save data after the insert-prozess has been running???

Maybe you want to use another hook, something with BEFORE ???

Then it would make sense, that you manipulate data BEFORE you SAVE/INSERT the DATA
and not FIRST SAVE/INSERT the DATA and THEN START to manipulate, then it is already to late to manipulate data, because the saving process already has been done!

EDIT: Similar post ???..

Hi thanks for your reply. I am following the after insert example in the velo doc: Combine several item fields together using an afterInsert hook .
This seems to be the exact example that I want to use. As I understand it, I thought that beforeInsert was when you want to modify data before writing to the table. I don’t want to modify the first and last name columns. I just want an additional column with the full name.

I am not sure how your link is related to my question.

If you want to use a hook to do this, you will need beforeInsert. See this quote in the API docs for after insert. If you want to modify the content being inserted to the collection, you must do so before it is inserted.

“Because the afterInsert hook is called after the insert() is executed, it cannot affect the item that is inserted into the collection. It can only affect the item returned by insert() .”

1 Like

I will try beforeInsert again… But I am confused about why it should be a beforeInsert. The afterInsert example in velo docs is pretty much exactly what I am doing: https://www.wix.com/velo/reference/wix-data/hooks/afterinsert . In contrast, the beforeInsert example shows changing the inserted string from lower to uppercase. That is modifying the user input so I get how that would be beforeInsert. My example does not modify user input. I don’t want to modify the user input: The firstName and lastName should remain separate fields and not modified at all from the user input. What I do want is to aggregate them for an additional field in my collection that is not in the form. I am honestly confused how my example differs from Velo afterInsert example and why mine would need beforeInsert if theirs doesn’t.

Is an item an entire row in the dataset (ie the info from one form submission), or is it the input for a single field? Perhaps that is where I am misunderstanding.

Their example is below.

export function myCollection_afterInsert(item, context) {
4  let hookContext = context;  // see below
5
6  //aggregate the content from several fields into one
7  item.combinedSentence = `Customer: ${item.lastName}, ${item.firstName}: Purchases: ${item.purchases}, Item Returns: ${item.returns}`;
8
9  return item;
10}
11
12/*
13 * hookContext:
14 *
15 * {
16 *   "collectionName": "myCollection",
17 *   "userId":         "f45jf8d2-grkj-2opd-4ovk-9rfj4wo5tvj3",
18 *   "userRole":       "siteOwner"
19 * }
20 */

Do I need to have used Velo for the form itself. Should I have written my own insert?

Here at this point i must say, the DESCRIPTION of AfterInsertHook is really very confusing.

After reading it again and again and again, i was so confused, that i already believed that it was really doable with the AfterInsertHook, although i was pretty sure with my first statement.

But of course Amanda must be right, already the name of the hook itself tells you that the hook should be triggered after some data was inserted into the DB, or if you use BeforeInsert, that means the hook is triggered before INSERTING-PROCESS starts.

Anyway, the discription was confusing for me, especially when your english is not 100%.

@russian-dima Thanks again for your response. If I use this code should it work? I don’t understand the hook context thing. Do I need to write something for that?

export function collection_beforeInsert(item, context) {item.fullName = `${item.firstName} ${item.lastName}`;
    console.log(item.fullName);
    return item;
}

So ok, let’s have a closer look onto all the little substeps.

  1. User enters your page
  2. User see your form and fill it with data.
  3. User clicks the submit-button.
    So if till here you seted-up everything the right way and you did it using a dataset (which connects your page with your database in the background), then at least now, you data must have been saved inside your database.

Till here normaly no coding needed, because all this can be done without any code.
The HOOKS you were talking about are needed if you want to change the flow of your setup.

For example like in your case → to calculate or modify first BEFORE you start to save your data of your form.

And this is exactly the point the case where you need a HOOK.

How this hook change the flow?

It changes the flow, because now, BEFORE the data will be saved → FIRST THIS SETTED HOOK WILL BE ACTIVATED AND WILL CHECK WHICH FUNCTION WAS ADDED/BUILD-IN BY USER.

And in this HOOK you define what has to be done additionaly, BEFORE your data will be INSERTED (at least saved).

Back to this question…

Is an item an entire row in the dataset (ie the info from one form submission), or is it the input for a single field? Perhaps that is where I am misunderstanding.

  1. Yes an ITEM is an ENTIRE-ROW, holding all DATA of the ITEM.

In coding language → An OBJECT, which holds differnt type of data, like further objects, arrays, strings, numbers or boolean-values.

An ITEM with all it’s values.

1 Like

@russian-dima thanks so much for your replies and explanation. I really appreciate it. I got my code working and my collection now has fullName. I am now trying to aggregate two tag fields resulting from 2 multiCheckBox questions into one array of tags. I wrote a function that works if both fields are not null but cannot figure out the right code to concatenate these two fields if one or both are null. I have tried if/else statements to check if tags1 or tags2 if one array is null and have tried to filter out null arrays. Even after I looked up the tag object in velo docs to see how I can extract info from them, I can’t figure it out.
Do you have any idea for how to solve this? I don’t know if I am having issues due to not being a javascript person (have previously mostly used python) or if it is a wix/velo thing.

Below is the simple function (without trying to filter null tags)

f **unction**  combineTags ( tags1 ,  tags2 ) { 
    **let**  allTags  = []. concat ( tags1,tags2 ); 
    **return**  allTags; 
} 
1 Like

So, let’s inspect your code a little bit more.

Let’s say you have two ARRAYS (this is exactly what you get from a CheckboxGroup or from an SelectionTag-element as VALUE.

myArray1 = [“value1”, “value2”];
myArray2 = [“value3”, “value4”, “value5”]

Your wished result = …
myResultArray = [“value1”, “value2”, “value3”, “value4”, “value5”]; ???

Something like…

$w.onReady(function () {let tags = [];
        tags[0] = ["value1", "value2"];
        tags[1] = ["value3", "value4", "value5"];let children //= arr1.concat(arr2);for (let i = 0; i < tags.length; i++) {
        children=tags[0].concat(tags[i])if(i===tags.length-1) {console.log(children);}}});

EDIT: Sorry some corrections… (TEST THIS ONE)…

$w.onReady(function () {
    let tags = [];
        tags[0] = [""];
        tags[1] = ["value3", "value4", "value5"];
        tags[2] = [""];
        tags[3] = ["value7", "value8"];
    let myWishedResults = [];

    for (let i = 0; i < tags.length; i++) {
        if(tags[i].length>0) {myWishedResults = myWishedResults.concat(tags[i]).filter(Boolean);}
        if(i===tags.length-1) {console.log(myWishedResults);}
    }   
});

Hi is your beforeInsert code still working? I have similar code running on my site and it doesn’t work

export function videos_beforeInsert(item, context) {
let hookContext = context;
let newUrl = createPageSlugFromTitle(item.title, “en”);
item.slug = newUrl;
return item;
}

It works fine when using afterUpdate but doesn’t work with before/afterInsert