Batch replace relationships conditionally

I am currently trying to dump a live data source into neo4j. Here is an example of what I need to achieve:
Given a json that represents an item:

{"id": "0001", "category_id": "a1", "shop_id": "shop_x1"}

The database has the following 3 types nodes: Item, Category, Shop, each with unique ID.
I need to:
(1) create the Item node with ID "0001" if a node with the same id does not exist;
(2) replace the relationship (Item)->(Category), that is this item can only points to at most one category,
if the json field "category_id" is empty, then the resulting Item node should have no relationship to Category
(3) similarly, replace the relationship (Item)->(Shop); keep no relationship if "shop_id" is empty.

So far what I have come up with is the following:

    UNWIND $batch as row
    MERGE (i:Item {id: row.id})
    SET i += row
    REMOVE i.category_id, i.shop_id

    WITH i, row
    OPTIONAL MATCH (i)-[r:IS_CATEGORY]->(c:Category)
    DELETE r

    WITH i, row
    MATCH (c:Category {id: row.category_id})
    MERGE (i)-[:IS_CATEGORY]->(c)

    WITH i, row
    OPTIONAL MATCH (i)-[r:IS_SHOP]->(s:Shop)
    DELETE r

    WITH i, row
    MATCH (s:Shop {id: row.shop_id})
    MERGE (i) - [:IS_SHOP] -> (s)

This script tries to merge a new Item node, then remove existing relationship followed by the creation of the new one. However it breaks loose when "category_id" or "shop_id" is empty, with error node is missing.

If I replace the OPTIONAL MATCH with normal MATCH, it again does not work when "category_id" is empty. In this case, since no category is matched, all following WITH will cease to fire.

I've no idea how to achieve this behaviour, yet this seems a fairly common requirement, namely to update a node and all its relationships. Would appreciate any help, thanks.

So you want to to do a conditional update?

It's not built in, if you have only one condition you can use a WHERE to filter out the times where the property does not exists, for multiple ones you can use

FOREACH(x IN case row.category_id when null then [] else [true] | MERGE ...)

see