Upsert mutation with facet value usage in condition

Hi
I have to make a edge assignment mutation based on the facet value but the looks like the mutation condition is not properly capturing the the facet value from the query block.

e.g
If the schema has user and roles and users can only be a single role and the condition is also based on a “since” facet on the assigned_role edge predicate.

e.g.

type user {
user_name
assigned_role

}

type role {
role_name

}

user_name: string @index(exact) .
role_name string @index((exact) .
assigned_role: uid @reverse .

// Conditional mutation based on the facet value. The following query is not working as expected and looks like the facet variable ‘s’ is not properly propagated to the mutation condition and so the mutation is never done even if the existing data matches the condition.

upsert {
    query {
         var(func: eq(user_name, "xyz123"))  {
               u as uid
               assigned_role @facets(v as since)
         }
         var(func: eq(role_name, "admin"))  {
               r as uid
         }
    }
    mutation @if(eq(len(u), 1) AND lt(val(v), "2020-10-30T10:10:10Z")) {
  	set {
    	     uid(u) <assigned_role> uid(r) (since="2020-10-30T10:10:10Z") .
  	}
    }
}

As the date are the same you should use “less than or equal to” if you use lt it would never trigger.

upsert {
  query {
    q1(func: eq(user_name, "xyz123"))  {
      u as uid
      user_name
      assigned_role @facets(v as since)
      }
      me(){
        T0 as max(val(v))
      }
    q2(func: eq(role_name, "admin"))  {
      r as uid
      role_name
      }
    }
    mutation @if(eq(len(u), 1) AND le(val(T0), "2020-10-30T10:10:10Z")) 
      {
      set {
        uid(u) <assigned_role> uid(r) (since="2020-10-30T10:10:10Z") .
        uid(u) <user_name> "xyz123" .
        uid(r) <role_name> "admin" .
      }
    }
}

BTW, this trick just works with one to one, that’s something in the backlog to be improved.

Thank you Michel, the mutation works now.

The trick is the missing additional query block which triggered the mutation condition.

    me(){
        T0 as max(val(v))
      }

Hi @MichelDiz

The above solution works if the user_name “xyz123” already exists but in the case of a new user_name, the upsert fails with

Invalid argment 2020-10-30T10:10:10Z. Comparing with different type

My assumption why this fails is that the max(val(v)) evaluates to 0 in the case of a non-existing user_name and the conditional expression le(0, “2020-10-30T10:10:10Z”) fails with the above message.

Is there workaround if the node does not exist and has to be created.

The example I have used a conditional upsert, if you still wanna the same behave and add a new behave (just like an “if, else if”) you have to add one more (or multiple conditionals blocks) with the rule you wanna. e.g:

mutation @if(eq(len(u), 0) AND NOT le(val(T0), "2020-10-30T10:10:10Z")) 
      {
      set {
        _:New <assigned_role> uid(r) (since="2020-10-30T10:10:10Z") .
        _:New <user_name> "xyz123" .
        _:New <role_name> "admin" .
      }
    }

Adding this block to the previous query, you would create a new node based on the new params. Are several ways of doing it tho.

The usual Upsert Block has this behave, but when we use a Conditional Upsert, we are basically saying to Dgraph that we wanna control that behave manually.