# Soft Delete

**URL:** <https://discuss.dgraph.io/t/soft-delete/11337>\
**Category:** GraphQL\
**Tags:** kind:feature\
**Created:** [November 6, 2020, 7:03pm UTC](https://discuss.dgraph.io/t/soft-delete/11337 "2020-11-06T19:03:05Z")\
**Posts on this page:** 2\
**Page:** 1

<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:** [November 6, 2020, 7:03pm UTC](https://discuss.dgraph.io/t/soft-delete/11337/1 "2020-11-06T19:03:05Z")

</div>

I am looking at the possibility of adding soft deletes into my graph. I am thinking this would be useful to restore accidentally deleted data. Thinking there should be a clean up process periodically to delete any soft deleted nodes after a given duration. The more I think about how I might do this, the more I think of how nice it would be as a core feature.

Here is what I am thinking so far to accomplish this.

- Map a delete predicate (or maybe even and edge for user tracking) onto every type that needs a soft delete.
- To help simplify DQL queries, use the `@dgraph` directive to map to a single predicate instead of the GraphQL type dotted notation used for predicates.
- Add `@auth` query rules that prevent users from reading nodes that have this soft delete.
- Somehow add a query rule that bypasses this rule above for when users want to search for deleted nodes as well.
- Create a script that cleans up the database permenantly deleting any nodes that have been pending delete for X days.

Has anyone else implemented soft deletes? How did you do it?

@chengxuncc I found an [old post](http://discuss.hypermode.com/t/how-to-query-node-that-doesnt-has-predicate/5542) where you did something similar to this before GraphQL, how is that working for you?

---

<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:** [November 7, 2020, 9:32am UTC](https://discuss.dgraph.io/t/soft-delete/11337/2 "2020-11-07T09:32:48Z")

</div>

I think this feature would be also very nice to have.

But I think it should be possible today using @auth directive? You could just extend the permission query to also check the **deletedAt** field? I will try to stitch something together, brb.

**Edit** Here is a working example:

Schema:

```auto
type Foo
  @auth(
    query: {
      and: [
        {
          or: [
            {
              rule: "query {queryFoo(filter: {not: {has: deletedAt}}) {deletedAt}}"
            }
            { rule: "{$SHOW_SOFT_DELETED: {eq: \"true\"}}" }
          ]
        }
        {
          rule: "query($USERNAME: String!) { queryFoo {owner(filter: { username: {eq: $USERNAME }}) { username }}}"
        }
      ]
    }
  ) {
  owner: User!

  deletedAt: DateTime @search

  content: String!
}

```

`queryFoo { content } ` will now return only Foos that don’t have a deletedAt Timestamp set.

SoftDeleting an object will now work using the `updateFoo` mutation and setting the timestamp. Regular delete would still work.

To allow also querying deleted objects, set **VIEW\_SOFT\_DELTED** to **true** in your JWT.  
I must admit, that this of course very inconvenient and requires the client to either:

- Always request two JWTs on login (one for normal operation, one for allowing to see soft-deleted nodes)
- Request the tokens ad-hoc

Either way, the client would need to switch tokens to get the required functionality. So integrated soft-delete would be obviously the preferred way.

**Edit2**  
The more I think about it, the functionality you described (especially the requirement to bypass the filtering) is already implemented using `update` mutations for softDelete (setting the flag) and use filtered `query` to optionally filter out soft-deleted content or show them. Am I right?

Let’s continue this discussion here:

> [@(Cascade)-Delete Directive](http://discuss.hypermode.com/t/cascade-delete-directive/11342):
>
> I know that this question has come up multiple times now but I want to express the importance of such a feature. Also this thread could be used to track this feature as I think that the other threads rather present workarounds to this currently missing functionality. Suggested Schema: directive @delete(soft: Boolean, cascade: Boolean, fields: [String]) on OBJECT | INTERFACE directive @showDeleted on OBJECT | INTERFACE type Foo @delete(cascade: true, fields: ["bars"]) { bars: [Bar!] foobar…
