campoy commented :
Hi all,
Sorry for the delay! I’m trying to better understand this feature request.
If I understood correctly when you insert the same edge multiple times you’d like to sometimes specify that the previous facets should be merged with the new ones.
What we have now
Currently, if we have a predicate met
between harry
and voldemort
which would have been created with the following mutation:
{
set {
_:harry <name> "Harry" .
_:voldemort <name> "Voldemort" .
_:harry <met> _:voldemort (inYear=2001) .
}
}
Currently, in order to add a new facet, e.g. likes=false
, we need to first fetch the previous facets attached to the predicate so we can then merge them on the client side and send them all back in a new mutation that would look something like the following:
{
set {
<0xb> <met> <0xc> (inYear=2001, likes=false) .
}
}
So if we now run the following query, we’ll get both the inYear
and likes
facets:
{
q(func:eq(name, "Harry")) {
uid
name
met @facets {
uid
name
}
}
}
Which returns:
{
"extensions": {...},
"data": {
"q": [
{
"uid": "0xb",
"name": "Harry",
"met": [
{
"uid": "0xc",
"name": "Voldemort",
"met|inYear": 2001,
"met|likes": false
}
]
}
]
}
}
Proposal
Fetching all facets before adding a new one can be sometimes complicated, requires transactions, and seems to not be the easiest way to add one more facet to an existing predicate.
We would like to be able to provide syntax for the following cases:
- we want to remove all previous facets
- we want to replace all previous facets with a new set
- we want to keep the existing facets and add a new set
Currently, (1) is simply done by not passing any facets.
Similarly, (2) is done by passing a list of facets in the mutation.
So we need to provide a new syntax for (3). Since the N-Triples specification does not provide any support for facets, I would recommend simply adding a +
right before the parentheses grouping the facets.
So given the previous dataset, where only the inYear
facet exists between Harry (0xb)
and Voldemort (0xc)
, we have four different cases:
-
<0xb> <met> <0xc> .
: the resulting predicate has no facets, as before.
-
<0xb> <met> <0xc> (likes=false) .
: the resulting predicate has only the likes
facet, as before.
-
<0xb> <met> <0xc> +(likes=false) .
: the resulting predicate has both inYear
and likes
facets.
-
<0xb> <met> <0xc> +() .
: the resulting predicate keeps the same facets as before, just inYear
.
And now, in JSON
For completion, the corresponding JSON mutation would look like the following:
{
"set": [
{
"name": "Harry",
"met": {
"name": "Voldemort",
"met|inYear": 2001
}
}
]
}
In order to add a new likes
facet, the mutation would now look like the following:
{
"set": [
{
"uid": "0xb",
"met": {
"uid": "0xc",
"met|likes": false
}
}
]
}
This mutation would act as <0xb> <met> <0xc> (likes=false) .
, removing the previous facets.
So how do we indicate that the previous facets should be kept in JSON format?
We have two options, the first one is simply not to support this use case in JSON. This might be a decent temporary solution but eventually, we’ll have to fix it.
The first solution that comes to mind is to use the same syntax we have now for facets pred|facet
but combine it in a way that makes it so the change would be backwards compatible. Facet names can’t contain the character @
, so let’s use it to add a pseudo facet @keep
with a boolean value (set to false by default).
When this is set to true, the previous facets will be conserved similarly to the +()
syntax for RDF.
So in order to add a new likes
facet, we could write:
{
"set": [
{
"uid": "0xf",
"met": {
"uid": "0x10",
"met|likes": false,
"met|@keep": true
}
}
]
}
This would act exactly as <0xb> <met> <0xc> +(likes=false) .
, and the resulting predicate would have both likes
and inYear
facets.
What do you all think?