Not sure I am not overlooking something, but is there an easy way to replace only the part of data? Ideally defined by a path.
It seems the only way is to do two queries, the first which sets something to null, and the second with actual data.
Do(
Update(ref, { data: { state: null } }),
Update(ref, {
data: {
state: {
type: 'success',
},
},
}),
);
You do not need two queries. Update should take care of it. Here is an example of order
document where I add a new object address
and then update a value in address
.
Get(Ref(Collection("orders"), "262998629034230290"))
{
ref: Ref(Collection("orders"), "262998629034230290"),
ts: 1587073887770000,
data: {
client: "john",
items: ["a", "b"],
price: 10.5,
status: "new"
}
}
>> Time elapsed: 569ms
Update(Ref(Collection("orders"), "262998629034230290"), {data: { address: { street: "MLK Ave", City: "NY"}}})
{
ref: Ref(Collection("orders"), "262998629034230290"),
ts: 1591989255520000,
data: {
client: "john",
items: ["a", "b"],
price: 10.5,
status: "new",
address: {
street: "MLK Ave",
City: "NY"
}
}
}
>> Time elapsed: 452ms
Update(Ref(Collection("orders"), "262998629034230290"), {data: { address: { City: "NJ"}}})
{
ref: Ref(Collection("orders"), "262998629034230290"),
ts: 1591989315850000,
data: {
client: "john",
items: ["a", "b"],
price: 10.5,
status: "new",
address: {
street: "MLK Ave",
City: "NJ"
}
}
}
>> Time elapsed: 315ms
Sorry I did not explain the issue properly. Yes, we can update part of the address, but what if we want to override address entirely, because it’s tagged tagged union / sum type? Imagine:
type Address = { type: 'short', street: string } | { type: 'long', street: string, city: string }
Changing type with Update means, a short type can have a city because it was not deleted.
You can use Merge
to curate the object passed to Update
.
Update(
ref,
{
data: Merge(
Select('data', Get(ref)),
{ state: { type: 'success' } }
)
}
)
faunadb-fql-lib
from @eigilsagafos has a DeepMerge function.
You should be able to use like
Update(
ref,
DeepMerge(
Get(ref),
{ data: { state: { type: 'success' } } }
)
)
I started working on a lens library for faunadb, based on shades, where it’s really easy to update a property deep in some object. That’s done by composing Merge
down to the desired object.
I doubt you’ll want to refactor everything around this but I’ve enjoyed playing with it. You can use it like this:
set(getRef(), path('data', 'state'))({ type: 'success' })(ref)
Unfortunately no, this does the same thing as Merge. It overrides the state, not replace it.
I will rephrase it again. FQL lacks the method to replace (not merge) the part of data. Therefore, we have to set it to null and then set it to desiderated value.
Ok. I might not have gotten it right for your case.
Merge
is a shallow operation, so it will work if you go down to the right level.
Can you provide a precise before and after data
object. I can make and actually test the query against it. Previous code was just off the top of my head.
The same as in the first message. I need to replace the data state (property state of a data object). The state is a tagged union, it can have various props. When we want to set a new state, we want to purge everything that has been there.
Do(
Update(ref, { data: { state: null } }),
Update(ref, {
data: {
state: {
type: 'success',
},
},
}),
);
-
It’s a bummer that I can no-longer edit my previous post to highlight what I did wrong
-
@Daniel_Steigerwald I did see your original post. I asked about the rest of the structure of the data to make sure you and I were really looking at the same the data, and to understand the complexity of that data… I will make some assumptions.
-
I definitely messed up my understanding of Merge
. To anyone and everyone that I suggested that Update
and/or Merge
work like Object.assign
, I apologize. It’s actually like lodash _.merge
function.
-
Remember that there is the Replace
function, in addition to Update
.
Ok. That means you still have some options, but will need to compare the complexity with what you are already doing. I am assuming that the document is much more complex, but don’t know without sharing more. The new example should get the point across though.
new option A: if by chance state
is the only field under data
then there is no added value to the extra object – Everything under state
can be directly under data
. Document with state
wrapper and another without it would be isomorphic. You can use Replace
every time instead of Update
. My guess is not so easy! Just putting it out there, though!
new option B: You can use Replace
and reconstruct the rest of the document with Select
. This might be okay if there is only one, maybe two fields other than state
, but it would get out of hand quickly.
Let(
{
ref: Ref(Collection('Test'), '268352561226973696'),
instance: Get(Var('ref'))
},
Replace(
Var('ref'),
{
data: {
state: {
type: 'success'
},
field1: Select(['data', 'field1'], Var('instance')),
field2: Select(['data', 'field2'], Var('instance')),
}
}
)
)
new Option C: I’m out of ideas.
new Option D: Wait for Fauna to implement Assign
function, to complement Merge
? I’m out of good ideas anyway.
Or just keep on keepin’ on how you’re doing. Only functional difference is [1 Read + 1 Write]
vs [2 Write]
operations.
As for flatenize, I can’t. It will be the same problem. How to remove obsolete props? Also, we can not flatenize more tagged unions. Algebraic data types exist for a reason.
Two updates and waiting for a new FQL function. Thank you for the answers.
I would abstract it away for now in your own function @Daniel_Steigerwald (if that is an option, not sure if you are using a driver), a new function would probably do more or less the same.