TL;DR: Use the items validation keyword to specify the data type of the elements of arrays in your js-data schema to avoid unexpected results when serializing records, e.g. for saving.
The setup
I was using js-data v3 with a schema containing an array field recently, and came across some initially baffling behaviour. I had a fooSchema that included a field definition along these lines:
1 2 3 4 5 6 7 8 9 |
import { Schema } from 'js-data'; const FooSchema = new Schema({ // ... barIds: { type: 'array', }, // ... }); |
A Foo object could have many associated Bar objects, and the API supplying the data specified them by including an array of their integer ids in the barIds field. Simple enough, and the above worked perfectly while consuming the output of the API. The unexpected behaviour didn’t start until I tried to send the array back to the API to update the record.
Serializing the array
When calling the save method on a Record , the defined Mapper serializes it with the toJSON method. Given the above schema, a record with barIds === [2, 3, 5] was getting converted to the JSON field barIds: [{}, {}, {}]. The length of the JSON array was always equal to the length of the underlying data array, but it never contained anything except empty objects instead of the desired relationship information.
A simple solution
When an array field in a record with a schema is serialized by js-data, each element is mapped to an empty object unless a valid JSON Schema for the element is specified. This choice of defaulting to {} happens in the Schema#pick method, when the type property of the schema is 'array'. To prevent this, simply specify the expected schema for the array elements in the schema for the records. In my case since the ids are numbers, this meant:
1 2 3 4 5 6 7 8 9 10 |
import { Schema } from 'js-data'; const FooSchema = new Schema({ // ... barIds: { type: 'array', items: { type: 'number' }, }, // ... }); |
The items validation keyword specifies how the elements of an array-type property should be treated. If not specified, the default is to treat them as objects. If the array contains actual related elements, then a js-data schema could be given, for example bars: BarSchema. Otherwise, any valid JSON Schema definition should provide the desired results.