# How to upsert using GraphQL?

**URL:** <https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931>\
**Category:** GraphQL\
**Tags:** kind:question\
**Created:** [August 31, 2020, 6:08pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931 "2020-08-31T18:08:20Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![iyinoluwaayoola](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/iyinoluwaayoola/32/4282_2.png) [@iyinoluwaayoola](https://discuss.dgraph.io/u/iyinoluwaayoola)\
**Post date:** [August 31, 2020, 6:08pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/1 "2020-08-31T18:08:20Z")

</div>

Hi there,

Seems basic but I must be missing something… How can I perform an upsert operation using GraphQL? I can upsert using DQL but when I do, my inverse predicate doesn’t get linked, so I need a GraphQL upsert.

Thanks.

---

<div class="post-metadata">

**Author:** ![amaster507](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/amaster507/32/4123_2.png) [@amaster507](https://discuss.dgraph.io/u/amaster507)\
**Post date:** [August 31, 2020, 6:16pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/2 "2020-08-31T18:16:38Z")

</div>

This was one of the reasons the developers of Dgraph needed to invent DQL (GraphQL±) you can read more about that at:

> **[Building a Native GraphQL Database: Challenges, Learnings and Future - Dgraph...](https://dgraph.io/blog/post/building-native-graphql-database-dgraph/)**
>
> “GraphQL is not a Graph DB query language — it’s a replacement for REST APIs.”
> That’s my standard opening statement whenever talking about Dgraph’s choice of the query language.

To answer your question directly,

> [@iyinoluwaayoola](#):
>
> How can I perform an upsert operation using GraphQL?

You will have to do it in 2 or more queries/mutations with a client side script.

> [@iyinoluwaayoola](#):
>
> I can upsert using DQL but when I do, my inverse predicate doesn’t get linked

Ah, the downside of using DQL and GQL together. With DQL you have to define every single predicate and the GQL equivalent reverse predicate. Do if you are changing the author on a Post you would need to set both `Post.author` and `Author.hasPosts` to make it a full update. GQL generates alot of these extra steps needed in DQL for you making it easier, but again that has limitations as you are now aware.

---

<div class="post-metadata">

**Author:** ![MichelDiz](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/micheldiz/32/11873_2.png) [@MichelDiz](https://discuss.dgraph.io/u/MichelDiz)\
**Post date:** [August 31, 2020, 6:56pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/3 "2020-08-31T18:56:14Z")

</div>

> [@iyinoluwaayoola](#):
>
> How can I perform an upsert operation using GraphQL? I can upsert using DQL but when I do, my inverse predicate doesn’t get linked, so I need a GraphQL upsert.

What is your objective? you could potentially use a [custom DQL](https://dgraph.io/docs/graphql/custom/graphqlpm/) - But I believe that the “CRUD” like structure that the GraphQL does under the hood, do a kind of “upsert” behave.

As you have a “CRUD” like behavior based on your schema. I think you don’t need the upsert, unless you are doing something very specific and hard to accomplish with GraphQL alone.

---

<div class="post-metadata">

**Author:** ![iyinoluwaayoola](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/iyinoluwaayoola/32/4282_2.png) [@iyinoluwaayoola](https://discuss.dgraph.io/u/iyinoluwaayoola)\
**Post date:** [September 1, 2020, 1:08am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/4 "2020-09-01T01:08:49Z")

</div>

@amaster507 Thanks for your response.

> [@amaster507](#):
>
> You will have to do it in 2 or more queries/mutations with a client side script.

I understand there are current limitations in GQL but performing upsert operations should be atomic and are not desired in two steps, otherwise becomes a recipe for introducing inconsistencies in the database if there are two or more similar operations at once.

> [@amaster507](#):
>
> GQL generates alot of these extra steps needed in DQL for you making it easier, but again that has limitations as you are now aware.

Yes, I’ve been experimenting with both and can see that a lot of in-between steps are performed by the GQL layer (great job). Hence, I expected the GQL layer to support upsert behaviour as well.

@MichelDiz thanks for addressing this.  
I’m not sure if you mean I don’t need a `custom DQL` for upsert or don’t need upsert in general. My use case is simple, I’m receiving data from an external source and I transform them into Dgraph. If the node does not exist I add them, otherwise, I update them. Simple enough to use the `Add` and `Update` queries but I prefer to perform operations like this in an atomic form.

> [@MichelDiz](#):
>
> But I believe that the “CRUD” like structure that the GraphQL does under the hood, do a kind of “upsert” behave.

@MichelDiz Can you expand on this? When I use the `Add` mutation and the node with an `@id directive` exists, the operation is disallowed. Also, when I use the `Update` mutation and the node does not exist, then nothing gets updated. What I want is for either case to succeed when upserting.

---

<div class="post-metadata">

**Author:** ![amaster507](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/amaster507/32/4123_2.png) [@amaster507](https://discuss.dgraph.io/u/amaster507)\
**Post date:** [September 1, 2020, 1:17am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/5 "2020-09-01T01:17:40Z")

</div>

> [@iyinoluwaayoola](#):
>
> If the node does not exist I add them, otherwise, I update them. Simple enough to use the `Add` and `Update` queries but I prefer to perform operations like this in an atomic form.

Care to give your feedback on:

> [@GraphQL equivalient to Insert on Duplicate Key Update](http://discuss.hypermode.com/t/graphql-equivalient-to-insert-on-duplicate-key-update/9337):
>
> When using the @id directive with third-party IDs there are times when I want to do an insert/update depending if the data exists already or not. I know this can be done with DQL inside of a @custom directive, but then I am limited to field selection and deep graph modeling based upon the returned data. What would be nice, is if there was a way to indicate in a mutation if I want to update on duplicate key instead of error out. type Person { guid: String! @id name: String } mutation { …

---

<div class="post-metadata">

**Author:** ![iyinoluwaayoola](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/iyinoluwaayoola/32/4282_2.png) [@iyinoluwaayoola](https://discuss.dgraph.io/u/iyinoluwaayoola)\
**Post date:** [September 1, 2020, 2:47am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/6 "2020-09-01T02:47:58Z")

</div>

Sure @amaster507. Your post there outlines the same question I’ve raised. Indeed it gets increasingly complex when you have multiple updates that can either be an `Add` or `Update` operation. What I want here is to be able to perform these mutations in one request. If this works, there are great benefits when combined with external IDs (or when `UIDs` are known beforehand). It means I can perform deeply nested mutations in one request and not worry about the existence of leaf nodes.

For example:

```auto
type Person {
    personId: String! @id
    name: String!
}

type Vehicle{
    vehicleId: String! @id
    model: String!
    owner: Person
}

mutation {
    updateVehicle(input: {
        filter: {vehicleId: {eq: "thiscar"}},
        set: {
            model: "foo",
            owner: {
                personId: "thatperson",
                name: "bar"
            }
        }
    }
}

```

With an upsert operation, I’ll expect this query to succeed even if `thiscar` or `thatperson` does not exist and the same applies to the `add` operation. Currently, I’ll need to make at least 4 requests on the first run to achieve the same result. I can imagine situations where an upsert is not desired, but in theory, there can be a way to flag this behaviour.

---

<div class="post-metadata">

**Author:** ![MichelDiz](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/micheldiz/32/11873_2.png) [@MichelDiz](https://discuss.dgraph.io/u/MichelDiz)\
**Post date:** [September 1, 2020, 3:12am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/7 "2020-09-01T03:12:50Z")

</div>

> [@iyinoluwaayoola](#):
>
> I’m not sure if you mean I don’t need a `custom DQL` for upsert or don’t need upsert in general.

Yeah, I meant that. I thought that if Dgraph creates an “Update” it should behave as an “upsert”. But feels like it doesn’t. I haven’t used Dgraph’s GraphQL as much I should. I was assuming things that would make sense in my opinion and experience with GraphQL.

> [@iyinoluwaayoola](#):
>
> If the node does not exist I add them, otherwise, I update them.

So, that’s exactly what a Custom DQL would do using the [Upsert Block](https://dgraph.io/docs/mutations/upsert-block/) - So, you would create a specific GraphQL mutation for this.

Also, I think there is an internal ticket about Upsert Block natively in GraphQL, but not sure. I’ll check.

> [@iyinoluwaayoola](#):
>
> When I use the `Add` mutation and the node with an `@id directive` exists, the operation is disallowed. Also, when I use the `Update` mutation and the node does not exist, then nothing gets updated. What I want is for either case to succeed when upserting.

Humm, I was about to question that. It should at least throw an error in the Update mutation. Like “There is nothing to update”. That’s odd for me. Do we have a ticket about it? (on the issue/graphql part)

# Update

I just have checked, there’s no ticket internally or here on discuss about the Upsert Behavior. Also, we should have one about the Update mutation, that it should throw an error in case the node doesn’t exists.

---

<div class="post-metadata">

**Author:** ![iyinoluwaayoola](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/iyinoluwaayoola/32/4282_2.png) [@iyinoluwaayoola](https://discuss.dgraph.io/u/iyinoluwaayoola)\
**Post date:** [September 1, 2020, 3:34am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/8 "2020-09-01T03:34:25Z")

</div>

> [@MichelDiz](#):
>
> So, that’s exactly what a Custom DQL would do using the [Upsert Block](https://dgraph.io/docs/mutations/upsert-block/) - So, you would create a specific GraphQL mutation for this.

Indeed, thats what the Custom DQL will do but this route is not preferred because my GQL schema should enforce a database model/structure I.e., using directives like `@hasInverse`, `@id`, etc. If I now create a Custom DQL to perform operations like this, I will be bypassing the GQL layer that should enforce the schema, therefore potentially introducing major inconsistencies.

> [@MichelDiz](#):
>
> It should at least throw an error in the Update mutation.

This seems sensible to me. So far I see, I don’t get any error when there is nothing to update.

---

<div class="post-metadata">

**Author:** ![iyinoluwaayoola](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/iyinoluwaayoola/32/4282_2.png) [@iyinoluwaayoola](https://discuss.dgraph.io/u/iyinoluwaayoola)\
**Post date:** [September 1, 2020, 4:56am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/9 "2020-09-01T04:56:50Z")

</div>

> [@MichelDiz](#):
>
> It should at least throw an error in the Update mutation.

@MichelDiz, although this is slightly out of the scope of the question here, after reconsidering your point, I think the current behaviour is right according to GQL specs since this is technically not an error.

> [GraphQL](https://spec.graphql.org/June2018/)  
> If no errors were encountered during the requested operation, the `errors` entry should not be present in the result.

The user can query on `numUids` (the number of affected UIDs) and check if the operation actually performed an update.

---

<div class="post-metadata">

**Author:** ![andrewluetgers](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/andrewluetgers/32/4986_2.png) [@andrewluetgers](https://discuss.dgraph.io/u/andrewluetgers)\
**Post date:** [November 16, 2020, 3:02pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/10 "2020-11-16T15:02:54Z")

</div>

What is the status of this, I’m a new user confused as to how the heck to accomplish basic functionality like add a new user with unique email. GQL enforcing schema, auto CRUD api are all great but it seems like a total bait and switch now it appears I have to drill into the advanced level of manually enforcing the schema constraints or accepting non-atomic multi-operation work-around? How is this not already a solved thing?

---

<div class="post-metadata">

**Author:** ![MichelDiz](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/micheldiz/32/11873_2.png) [@MichelDiz](https://discuss.dgraph.io/u/MichelDiz)\
**Post date:** [November 16, 2020, 5:11pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/11 "2020-11-16T17:11:56Z")

</div>

If you use the update op you should be fine. The upsert would be in cases like “if it doesn’t exist, create a new one”. GraphQL spec doesn’t cover that. You have to manually set up such verification and probably do 2 operations, one to query and verify on your end, another the create or update.

Also, there’s no news about this as this was a question. Not a request. Usually, popular requests are prioritized on the backlog.

---

<div class="post-metadata">

**Author:** ![andrewluetgers](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/andrewluetgers/32/4986_2.png) [@andrewluetgers](https://discuss.dgraph.io/u/andrewluetgers)\
**Post date:** [November 16, 2020, 7:27pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/12 "2020-11-16T19:27:11Z")

</div>

Thanks @MichelDiz will move forward as you prescribe. In practice not having upsert is not a deal killer.

---

<div class="post-metadata">

**Author:** ![chewxy](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/chewxy/32/4339_2.png) [@chewxy](https://discuss.dgraph.io/u/chewxy)\
**Post date:** [November 16, 2020, 10:44pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/14 "2020-11-16T22:44:04Z")

</div>

FYI we have internally made design docs for upserts in GraphQL, with @michaelcompton fearlessly leading the charge. It’ll be made public soon once we have hashed out the little deets.

---

<div class="post-metadata">

**Author:** ![phillip](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/phillip/32/5786_2.png) [@phillip](https://discuss.dgraph.io/u/phillip)\
**Post date:** [December 22, 2020, 8:09pm UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/15 "2020-12-22T20:09:22Z")

</div>

Hi, I could successfully use DQL upsert feature with GraphQL attributes including linked attributes.  
Drawback is the need of handling inverse edges manually.

```auto
upsert {
  query {
    q(func: eq(User.username, "john.doe")) {
      v as uid
    }
    
    q2(func: eq(Department.number, "1")) {
      dp as uid
    }
  }

  mutation {
    set {
      uid(v) <User.username> "john.doe" .
      uid(v) <User.email> "user@company1.io" .
      uid(v) <User.department> uid(dp) .
      uid(dp) <Department.members> uid(v) .
      uid(v) <dgraph.type> "User" .
    }
  }
}

```

After that a GraphQL query provides the information of linked attributes: User.department and Department.members (inverse edge).

```auto
query {
  queryUser(){
    username
    department {
      number
    }
  }
  
  queryDepartment(){
    number 
    members { 
      username
    }
  }
}

```

Result:

```auto
{
  "data": {
    "queryUser": [
      {
        "username": "john.doe",
        "department": {
          "number": "1"
        }
      }
    ],
    "queryDepartment": [
      {
        "number": "1",
        "members": [
          {
            "username": "john.doe"
          }
        ]
      }
    ]
  }
}

```

---

<div class="post-metadata">

**Author:** ![billybobthorton](https://avatars.discourse-cdn.com/v4/letter/b/dbc845/32.png) [@billybobthorton](https://discuss.dgraph.io/u/billybobthorton)\
**Post date:** [January 29, 2021, 12:45am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/16 "2021-01-29T00:45:15Z")

</div>

> [@iyinoluwaayoola](#):
>
> Simple enough to use the `Add` and `Update` queries but I prefer to perform operations like this in an atomic form.

Atomic is critical, I am in the same position

---

<div class="post-metadata">

**Author:** ![maaft](https://avatars.discourse-cdn.com/v4/letter/m/4af34b/32.png) [@maaft](https://discuss.dgraph.io/u/maaft)\
**Post date:** [January 29, 2021, 8:36am UTC](https://discuss.dgraph.io/t/how-to-upsert-using-graphql/9931/17 "2021-01-29T08:36:47Z")

</div>

It’s on the roadmap and coming 21.03 AFAIK

> **[Dgraph Product Roadmap 2021](https://discuss.dgraph.io/t/dgraph-roadmap-2021/12284)**
>
> Features Enterprise Features Multi Tenancy \[Dgraph 21.03\] (2021-Q1) Change Data Capture (with Kafka) \[Dgraph 21.03\] (2021-Q1) Audit logs \[Dgraph 21.03\] (2021-Q1) Learner Nodes \[Dgraph 21.03\] (2021-Q1) ACL integration with AD ACL...
