Mutation Upsert Cond does not seem to work with type checks

I Want to Do

I’d like to link two entities only if they have the same type. This is a follow-up issue related to my experiments described here

What I Did

Assuming I only want to link entities of type Entity as long as they exist, I figured something like this could do the job:

	q := `
	{
		from as var(func: eq(xid, "` + from.Value() + `")) {
			fromUID as uid
			fromType as dgraph.type
		}

		to as var(func: eq(xid, "` + to.Value() + `")) {
			toUID as uid
			toType as dgraph.type
		}
	}
	`

	link := &Entity{
		UID:   "uid(fromUID)",
		DType: []string{"Entity"},
		Links: []Entity{
			{UID: "uid(toUID)", DType: []string{"Entity"}},
		},
	}

	cond := `@if(gt(len(from), 0) AND gt(len(to), 0) AND eq(val(fromType), "Entity") AND eq(val(toType), "Entity"))`

	pb, err := json.Marshal(link)
	if err != nil {
		return nil, fmt.Errorf("json marshal: %w", err)
	}

	mu := &dgapi.Mutation{
		Cond:    cond,
		SetJson: pb,
	}


	req := &dgapi.Request{
		Query:     query,
		Mutations: []*dgapi.Mutation{mu},
		CommitNow: true,
	}

	resp, err := s.c.NewTxn().Do(ctx, req)
	if err != nil {
		return fmt.Errorf("txn Link: %w", err)
	}

Whilst this “succeeds” without any errors, these two entities don’t get linked, that is at least based on what I’m getting as a result of this query:

{
  q(func: has(xid)) {
   uid
   xid
   name
   links @facets {
    xid
    name
  }
 }
}

I can verify both of the linked entities are definitely of type Entity by running the following query:

{
  	var(func: has(xid)) {
            u as uid
			t as dgraph.type
	}
  
    node(func: uid(u)) @filter(eq(val(t), "Entity")) {
      type: val(t)
    }
}

Now, what I did observe is, when instead of the mutation cond I mentioned above I use the following one (which omits entity type check), the entities do get linked as expected:

cond := `@if(gt(len(from), 0) AND gt(len(to), 0))`

Is there something in the Cond I’m missing in terms of what are the allowed funs/values I can use in it? It would appear that I’m either missing something or I simply can’t check the type as per my original assumption.

Dgraph Metadata

dgraph version
$ dgraph version
[Decoder]: Using assembly version of decoder
Page Size: 4096

Dgraph version   : v20.11.0
Dgraph codename  : tchalla
Dgraph SHA-256   : 8acb886b24556691d7d74929817a4ac7d9db76bb8b77de00f44650931a16b6ac
Commit SHA-1     : c4245ad55
Commit timestamp : 2020-12-16 15:55:40 +0530
Branch           : HEAD
Go version       : go1.15.5
jemalloc enabled : true

For Dgraph official documentation, visit https://dgraph.io/docs/.
For discussions about Dgraph     , visit http://discuss.dgraph.io.

Licensed variously under the Apache Public License 2.0 and Dgraph Community License.
Copyright 2015-2020 Dgraph Labs, Inc.

The variables “From” and “to” are redundant. The variables fromUID and toUID should be used instead.

As far as I know, conditional upserts supports len only.

Other way of doing it.

upsert {
  query {
		q1(func: eq(xid, "` + from.Value() + `")) @filter(eq(dgraph.type, "Entity") {
			from as uid
			dgraph.type
		}

		q2(func: eq(xid, "` + to.Value() + `")) @filter(eq(dgraph.type, "Entity") {
			to as uid
			dgraph.type
		}
	}  
  
  mutation @if(gt(len(from), 0) AND gt(len(to), 0)) {
    set {
      (...)
    }
  }
  }

Hm, based on what I noticed here is that this works fine in Cond:

mu := &dgapi.Mutation{
		Cond:    `@if(not type(Resource) OR eq(count(~resource), 0))`,
		SetJson: pb,
	}

As for the query, I guess this could work, too (though this doesnt work at all but I guess that’s a different issue):

q1(func: eq(xid, "` + from.Value() + `")) @filter(type(Entity)) {
			from as uid
}

If it is not in the docs, neither in the test files. It potentially isn’t supported. If you tested and worked. Nice. Also, if you have succeeded and it isn’t documented anywhere. That might bring unwanted results. And it should have a unit test to make sure it is working as it should work. All developers are instructed to do the tests at the same time that they create the feature.

I recommend that you open an issue (for each approach with examples) to the docs team and the community support to take a look and prepare official documentation.

In the Upsert docs, there’s no mention of the use of functions other than len. As you can do any filtering and other logic in the query part.

Gotcha, makes sense and makes the code much cleaner, too :slight_smile: Thanks

1 Like