Embedded scripting functions inherit the context in which they are run. The this context of every embedded function is set to the current record on every invocation, which allows the function to read the fields of the record being updated.
CREATE film:dune SET ratings = [
{ rating: 6, user: user:one },
{ rating: 8, user: user:two }
];
UPDATE film:dune SET featured = function() {
return this.ratings.filter(
({ rating }) => rating >= 7
).map(({ rating, ...data }) => {
return {
...data,
rating: rating * 10
};
});
};[
{
featured: [
{ rating: 80f, user: user:two }
],
id: film:dune,
ratings: [
{ rating: 6, user: user:one },
{ rating: 8, user: user:two }
]
}
]this holds the record as it was before the statement, the same image that every other expression in a SET clause reads. A record that is being created has no earlier image, so inside a CREATE statement this is undefined, and reading a field from it fails with cannot read property 'ratings' of undefined. Instead, create the record first and set the scripted field with UPDATE, as above.
Linked records
A record link in this is a record ID, not the record it points to, so a path such as this.owner.name is undefined in JavaScript. To use fields of a linked record, pass them to the function as arguments. Arguments are SurrealQL expressions, so the path follows the links before the function runs, and the function receives the values in arguments:
CREATE tool:hammer SET name = 'Hammer';
CREATE person:one SET name = 'Ann', tool = tool:hammer;
CREATE car:one SET owner = person:one;
UPDATE car:one SET label = function(owner.name, owner.tool.name) {
const [name, tool] = arguments;
return `${name} with a ${tool}`;
};[
{
id: car:one,
label: 'Ann with a Hammer',
owner: person:one
}
]Where the value only combines fields, a computed field does the same without scripting, and stays current when the linked records change:
DEFINE FIELD label ON car COMPUTED owner.name + ' with a ' + owner.tool.name;