Upserting for a list of predicates

Hi, i’ve read through the upsert docs at https://dgraph.io/docs/mutations/#upsert-block but can’t figure out how to acheive the following scenario, help greatly appreciated!

I have a list of values that may or may not exist in dgraph. In a single upsert block, I want to query for nodes based on these predicates (e.g. (func: eq(uniqueValue, [“abc”,“def”,“ghi”]))). For each predicate, if no node/uid is found, I want to create a new uid and set uniqueValue to this value. Lastly I need to get back the complete list of uid-uniqueValue pairs, whether they existed already or were created by the upsert.

I can make this work if i use one upsert block per uniqueValue, but that does not perform very well for the amount of data. Is this possible?

Hi @RJKeevil, You can perform this mutation in one upsert block. I have written a sample upsert block below.

upsert {
  query {
    q1(func: eq(uniqueValue, "abc")) {
      v1 as uid
     uniqueValue
    }
    q2(func: eq(uniqueValue, "def")) {
      v2 as uid
      uniqueValue
   }
   q3(func: eq(uniqueValue, "ghi")) {
      v3 as uid
      uniqueValue
    }
  }
  mutation {
    set {
      uid(v1) <uniqueValue> "$val1" .
      uid(v2) <uniqueValue> "$val2"
      uid(v3) <uniqueValue> "$val3" .
    }
  }
}
1 Like

Thanks for the response, I will test straight away. So in the case that the uniqueValue already exists with a Uid, will the mutation be a no-op? Or will it be executed, but result in no change to the graph?

If any of the uniqueValue already exist, it will be executed but there will be no change(if you keep new uniqueValue to be the same as older).

1 Like

Thank you @minhaj , I almost have this working fully with the following code:

    values := []string{"abc","def","ghi"}
	var queries []string
	var mutations []*api.Mutation
	for i, value := range values {
		a := strconv.Itoa(i+1)
		queries = append(queries, fmt.Sprintf(`{q%s(func: eq(uniqueValue, "%s")) {v%s as uid uniqueValue}}`, a, value, a))
		mutations = append(mutations, &api.Mutation{
			SetNquads: []byte(fmt.Sprintf(`uid(v%s) <uniqueValue> "%s" .`, a, value)),
		})
	}

	request := &api.Request{
		Query:     strings.Join(queries, "\n"),
		Mutations: mutations,
		CommitNow: true,
	}

	response, err := dgraphClient.NewTxn().Do(context.Background(), request)
	util.Check(err)

	fmt.Println(response.Uids)

Interestingly, it only prints the Uids for uniqueValues that do not exist already in dgraph. Thats hopefully a good sign for efficiency, as it is detecting the others can be skipped? Unfortunately, I need those preexisting Uids too :slight_smile:

I could follow up with a second query for these, but I really want to do this in a single query if possible.

Can you show me the full JSON response of this mutation?

Unfortunately fmt.Println(string(response.Json)) just gives the following:

{"q1":[],"q2":[],"q3":[]}

I seem to get this for all upserts in the dgo client, perhaps that is a bug.

Can you tell me Schema of your use case which will help me to reproduce the error.

The code above should be everything you need to reproduce I think, but the Type for this Uid is called Key and it has the following predicates

type: string @index(hash) .
value: string @index(hash) .
uniqueValue: string @index(hash) .

I tried modifying the code above to include setting things like dgraph.type and these additional fields, but it made no difference for me.

Im running the latest dgo cleint (V200) and the Jun22 beta, but I think this happens on all versions, ill test in a sec.

I think you are starting with blank data every time you are performing the above upsert, that is why response.Json seems to be empty. I haven’t tried it on dgo yet, but if any of the uniqueValue is present already then response.json must not be empty. For the sake of simplicity, can you upload the complete code for the upsert and let me check. Otherwise, there must be some issues.

1 Like

You’re right, matching results are returned via response.Json, updated uids are present in the response.Uids. My dgraph instance was being inadvertently cleared between tests. Thanks!