Yes, you can use WATCH to implement an optimistic locking mechanism.
It adds some more complexity in the code though.
IMO, the granularity of the lock should be the tree itself (coarse locking),
because it looks hard to determine the optimal subset of keys to lock
depending on the operation.
Regarding the new requirements, you want to move from a tree to
a directed acyclic graph.
It is possible to store a graph with a similar closure table.
You could keep the desc keys unchanged, and for the asc keys
store the ascendant nodes with their immediate descendant.
So your example would be:
zadd asc:3 1 2:3
zadd asc:3 2 1:2
zadd asc:3 1 5:3
zadd asc:3 2 4:5
zadd asc:3 3 1:4
Please note node 1 is stored twice because it has 2 descendants.
It is up to the client to merge the two items in a single node when
the ascendants are retrieved.
Actually the definition of the desc and asc content is now completely
symmetrical, and the graph can be reversed by exchanging the content
of the two keys for all the nodes ...
Maintenance of this structure is even more complex (and probably
twice as expensive) than for the tree.
You should perhaps consider another storage engine, more adapted
to this kind of data. For instance, OrientDB and Neo4j are both excellent
open-source graph oriented databases for which it should be possible
to find Node.js drivers.
Best regards,
Didier.