Feature(s) impacted
Flattened Smart Fields rendering on Lists (and in general on the “Get List” route handlers).
Observed behavior
When a smart field is defined on a flattened record (i.e under some root and using the “@@@” separator) the data of the smart field is not calculated/retrieved with a list load command - only on an individual record data loads.
Expected behavior
The Smart Field should work like all smart fields.
Context
Assume the following example schema:
const managerSchema = new Schema({
first_name: String,
last_name: String,
});
const mainSchema = new Schema({
manager: managerSchema,
});
export default Schema(mainSchema);
Assume the following Liana collection configuration:
Liana.collection('Team', {
fields: [
{
field: 'manager@@@full_name',
type: 'String',
get: (record) => {
return record.manager
? record.manager.first_name + ' ' + record.manager.last_name
: 'no manager';
},
},
],
actions: [],
segments: [],
fieldsToFlatten: ['manager'],
});
Note - “manager” is flattened and “manager@@@full_name” is a smart field.
Additional Research
Diving into the code in forest-express-mongoose
- Specifically in the Projection Builder it does seem like the method findRequestSmartField
in the following section:
return this.schemaSmartFields
.filter((fieldName) => requestFieldsNames.includes(fieldName));
has a problem finding Smart Fields which are nested. the “requestFieldNames” at this point only contains “root” properties - but the “Smart Field” is defined like so:
{
field: 'someRootProp@@@calced_field'
}
This (maybe non standard way) of defining Smart Fields in a nested path works fine in other places in the system and the nesting is perfect - but I guess here in the Resources-Getter code tree things do not expect this.
I am looking for a workaround.
Additional Research
The top middleware here is requestUnflattener
which “hides” from the normal Liana pipeline the flattened fields coming in from the query. It replaces them with the “root” field.
This works fine for query building and parsing since specifying “rootField” will bring in any sub field/documents which is good enough for the flattener to fo “flattening” on the outbound data pipeline.
But, when it comes to Smart Fields that are explicitly defined using the internal “@@@” separator - they are not detected and the Deserializer would not be able to “know” they are part of the request.
In forest-express-mongoose
- Specifically in the “Projection Builder” the method findRequestSmartField
has the following section:
return this.schemaSmartFields
.filter((fieldName) => requestFieldsNames.includes(fieldName));
Finding Smart Fields which are nested requires them to be on the requestFieldsNames
. The “requestFieldNames” at this point only contains “root” properties.
Suggested approach for solution
- extend the
requestUnflattener
such that anyfields
that have been replaced by their parent will be preserved on a new “param” called "unflattenedFields` - this will have the original names as sent with the ‘@@@’ - Extend the ResourceSerializer to accept an additional parameter
unflattenedFields
that will be appended to thefieldsPerModel
param sent toSmartFieldsValuesInjector
so it can “find” smart fields to calculate based on that field. - Another fix to cover all bases would be to fix the QueryBuilder so it can append those same field to the ones sent to ProjectionBuilder so it can run the
findRequestSmartField
method on them and disable the projection (so to get all fields that a SmartField might use)
Workaround for now
I am moving all smart fields to root
Meaning - I am not defining smart fields with “@@@” in them.
In the above example I would define a smart field like so:
{
field: 'manager_full_name',
type: 'String',
get: (record) => {
return record.manager
? record.manager.first_name + ' ' + record.manager.last_name
: 'no manager';
},
},
Env
- Project name: WescoverContentAdmin
- Environment name: Private Development
"meta": {
"liana": "forest-express-mongoose",
"liana_version": "8.7.6",
"stack": {
"database_type": "multiple",
"engine": "nodejs",
"engine_version": "16.18.0",
"orm_version": "5.9.29"
}
}
Thanks!