The fields of a schema define the allowed content for the properties of the documents having this schema.
Simple Types
The Nuxeo Platform internal data model is based on the following data types:
String
: a Unicode string value.Long
: a 64-bit signed integer.Double
: a double-precision 64-bit IEEE 754 floating point number.Boolean
: a boolean data type.Calendar
: a date, more specifically an instant in time with milliseconds resolution.
Calendar Timezone
Because most storage layers are unable to store an instant in time with an associated timezone to interpret it, dates in the Nuxeo Platform are usually translated to the server timezone, and are read back with the server timezone.
For instance one could write a date as "1st January 2017 at 2pm London Time" but if the server is working in the Paris Time timezone, it would be read back as "1st January 2017 at 3pm Paris Time", because there is a one hour difference between London Time and Paris Time (this is a simplification of how timezones work but is sufficient here). The important point is that both "1st January 2017 at 2pm London Time" (the value written) and "1st January 2017 at 3pm Paris Time" (the value read) represent the same instant in time.
Arrays
A Nuxeo Platform field can also store an array of the simple types described above.
In JSON an array value would be represented for instance as:
["a", "b", "c", "d"]
Complex Types
A Nuxeo Platform field can also store a sub-document defined by a map of sub-field to value.
In JSON a complex value would be represented for instance as:
{
"foo": 1,
"bar": "something",
"baz": [42,1729]
}
Complex types can contain other complex types:
{
"foo": 1,
"bar": "something",
"baz": {
"name": "bob",
"address": "here",
"age": 12
}
}
Complex Lists
A Nuxeo Platform field can also store a list of complex types.
In JSON a complex list value would be represented for instance as:
[{
"foo": 1,
"bar": "something",
"baz": [42,1729]
},{
"foo": 2,
"bar": "something else",
"baz": [1,2,3,5,7,11]
}]
XSD Mapping
A standard set of XSD types are allowed in Nuxeo Platform schemas, and are mapped to the internal data model as follows:
XSD Type | Java Type |
---|---|
xsd:string | String |
xsd:normalizedString | String |
xsd:long | Long |
xsd:unsignedLong | Long |
xsd:integer | Long |
xsd:int | Long |
xsd:unsignedInt | Long |
xsd:positiveInteger | Long |
xsd:nonPositiveInteger | Long |
xsd:nonNegativeInteger | Long |
xsd:short | Long |
xsd:unsignedShort | Long |
xsd:double | Double |
xsd:float | Double |
xsd:decimal | Double |
xsd:boolean | Boolean |
xsd:datetime | Calendar |
xsd:date | Calendar |
xsd:time | Calendar |
Unset Values
All fields allow an additional unset value, which is expressed differently depending on the language (null
in Java or JavaScript for example) or storage used (NULL
in SQL databases, unset in MongoDB).
Some storage mechanisms, like MongoDB, distinguish between a null
value and an unset value, but Nuxeo Platform takes care that at the storage level there are only unset values, to minimize document size and for consistency.
For arrays and complex lists, no distinction is made between an unset value and an empty array/list; they are semantically equivalent for the Nuxeo Platform data model.
Default values
A schema can express that a field has a default value. When this is the case, it replace the unset value with this default. In particular this means that one can never read a null
from a field that has a default value.
Delta Updates
Since Nuxeo Platform 6.0 (NXP-15103) a new update model for Long
properties is available using DeltaLong
.
A DeltaLong
is stored as a Long
, but when used in the Java API to update a field (DocumentModel.setPropertyValue()
) it specifies that the update should be done as an increment at the storage level rather than as a replacement of the old value. This allows for concurrent updates that don't lose value.
The standard usage to add a value "count" to a property "myprop" is:
long count = 1;
Number oldValue = (Number) doc.getPropertyValue("myprop");
Number newValue = DeltaLong.valueOf(oldValue, count);
doc.setPropertyValue("myprop", newValue);
DeltaLong.valueOf(oldValue, count)
should be used in preference over new DeltaLong(oldValue, count)
because it can deal with the case where the old value is null
or already a DeltaLong
(the latter can happen if you're re-updating a property which hasn't been saved yet).
When using a SQL backend, this will emit code like (supposing the old value was 41):
UPDATE myschema SET myprop = myprop + 1 WHERE id = 'the-doc-id';
instead of:
UPDATE myschema SET myprop = 42 WHERE id = 'the-doc-id';
which gives different results if two threads are executing it at the same time.
For a MongoDB backend, the update will be done using:
db.default.update(
{ "ecm:id": "the-doc-id" },
{ $inc: { "myprop": 1 } }
)
instead of :
db.default.update(
{ "ecm:id": "the-doc-id" },
{ $set: { "myprop": 42 } }
)