Newbie question regarding best practice for saving (batch) and simultaneously check for patterns or existing nodes


(John) #1

Hey guys,
have a newbie question regarding GRANDstack implementation/structure.

I want to do something like this:
when saving an order (buy/sell transaction), I want to also check if there are any related orders that can be grouped into a trade in this simple pattern: (o:Order)-[:IN_TRADE]->(t:Trade).
If there are no trades open, then a (t:Trade) should also be created and related to the (o).
If there is one open trade position, the newly saved (o) should be related to that already existing (t).

So, my idea so far is that the grouping can be done by a property that exists in the order-nodes (o:Order {symbol :"X"}) together with a property in a related trade-node (t:Trade {isOpen:true}).

Then, also, after a new (o) and relation is added to a (t), there needs to be a check whether (t) should be still {isOpen:true} which im thinking can be done by calculating all related (o {quantity: int}) and if the sum is = 0, then the trade is closed and t.isOpen SET to false.

My question is... how and where this should be done?

Im thinking that ideally one don't want to make a lot of requests between client and server for each MATCH, MERGE, CREATE etc?
But so far I have been unable to create a cypher query that can do all of this logic, is it even possible or should it be done in the cypher-part?

The other way I see is to use the basic automatically generated queries and mutations done with makeAugmentedSchema from my graphQL schema and then do the calculations in the client part, but that would then make a lot of back and forth between client-server.

I don't have much experience so im not sure how things like this "should" be structured.

It doesn't seem that it would be good with a lot of round-trips between client and server/db.
Is seems to me to make more sense that when sending a CreateOrder mutation to the server/db, the logic should happen on the server so that there doesn't need to be a bunch of back and forward??
But how is that done? Should that be in the resolver-functions of the graphQL? But then I would need to also figure out how to make all that happen in cypher and so far haven't succeeded.

Thanks for any feedback!


(William Lyon) #2

I would suggest trying to figure out how to do this in a Cypher query and then you could use a Cypher directive on a mutation field to map this query to a custom mutation.

So it sounds like your query has some conditional logic? Perhaps something like this helps:

MERGE (o:Order {id: $orderId})
WITH o, SIZE( (o)-[:IN_TRADE]->(t:Trade {isOpen: true})) AS open
WITH CASE WHEN open > 0 THEN [1] ELSE [] END AS isOpen
FOREACH ( _ IN isOpen |
  // this block is only exectued if open > 0
  CREATE (o)-[:IS_IN]->(t)
  // TODO: check if trade should be closed etc
)