This section of the docs shows what I think I’m after, but I’m rather lost and have not managed to replace any nested value yet.
I have a nested structure of unknown levels, generated from Ecto results and Arbor. Simplified:
%Post{
id: 1,
show_reply_form: false,
children: [
%Post{
id: 2,
show_reply_form: false,
children: [
%Post{
id: 4,
show_reply_form: false,
children: []
}
]
},
%Post{
id: 3,
show_reply_form: false,
children: []
}
]
}
There’s always one root Post struct.
I need to update a couple of keys’ values (e.g., :show_reply_form to true) for the potentially nested struct/map that has a given id. The id is coming from a user-triggered LiveView event value.
As part of stumbling through, it seemed as if I needed to change this line from the documentation:
combine(fn recursive -> some() ~> (recursive() ||| matching()) end)
to the following in order to avoid errors:
combine(fn recursive -> some() ~> (recursive ||| matching(_)) end)
Here’s what I’m trying:
target_id = 4
path_to_post =
combine(fn recursive -> some() ~> (recursive ||| matching(_)) end)
~> matching(%{id: _})
~> path(1 / :id) # ???
~> filtering(&(&1 == target_id))
test = Pathex.set!(post_tree, path_to_post, "x") # just testing replacement
It’s not erroring, but nothing is replaced.
I do have my own (probably horrible) function that’s working, but I think it’s not memory-efficient and runs through more of the posts than necessary:
# Prevents recursing into children of target post, but still recurses through the rest
defp set_post_data(%{id: post_id} = post_tree, target_id, new_values) when post_id == target_id do
# Root post is target; no recursing required
Map.merge(post_tree, new_values)
end
defp set_post_data(%{children: children} = post_tree, target_id, new_values) do
case Enum.find_index(children, &(&1.id == target_id)) do
index when is_integer(index) ->
# One of the children is the target
new_children = List.update_at(children, index, &(set_post_data(&1, target_id, new_values)))
Map.put(post_tree, :children, new_children)
_ ->
# None of the children are the target; recurse
new_children = Enum.map(children, &(set_post_data(&1, target_id, new_values)))
Map.put(post_tree, :children, new_children)
end
end
new_values = %{
show_reply_form: true,
}
post_tree = set_post_data(socket.assigns.post, target_id, new_values)
So I thought I’d see if I could use Pathex. But I’m very open to using a better function than mine, too. ![]()
Thanks.


















