# How to Soft Delete with MongoDB and Go

If you have to implement an API with CRUD operations on **MongoDB** with **Go**, but with the caveat that the documents on a collection had to be deleted using the  [soft delete](https://en.wiktionary.org/wiki/soft_deletion) pattern, then continue reading to find out how. 

> 
You can find the full source code here:
 [https://github.com/arielcr/soft-delete-mongodb-go](https://github.com/arielcr/soft-delete-mongodb-go) 

If you are using a *SQL* database this is a common and easy task, and probably easier if you do it on any other language with a  [framework](https://laravel.com/) . I searched about what was the best way to do this in **MongoDB**, and I found several implementation examples, but none of them were very clear or straightforward, and there were just a few examples in **Go**.

So, after looking at the  [official MongoDB driver for Go](https://github.com/mongodb/mongo-go-driver) and the examples on the  [MongoDB documentation](https://docs.mongodb.com/drivers/go/), it all ends up on having a well-defined struct for your document with the right *json* and *bson* attributes.

So, let's say you have a *User* document, with the following struct:

```
type User struct {
	ID        primitive.ObjectID `json:"id" bson:"_id"`
	Name      string             `json:"name" bson:"name"`
	Email     string             `json:"email" bson:"email"`
}
``` 

If you want it to support the *soft delete* pattern, you have to include the `deleted_at` field:

```
type User struct {
	ID        primitive.ObjectID `json:"id" bson:"_id"`
	Name      string             `json:"name" bson:"name"`
	Email     string             `json:"email" bson:"email"`
	DeletedAt time.Time          `json:"-" bson:"deleted_at,omitempty"`
}
```

Notice how we are excluding this field from the *json* response with the `-` attribute because we don't want this to be returned as part of the response data, also take a look at the `omitempty` *bson* attribute, so this does not get into the document if it is not specified. 

First, we insert our *User* (we don't have to include the `deleted_at` field):

```
user := entities.User{
		Name:  "John Doe",
		Email: "john@doe.com",
	}

_, err := r.collection().InsertOne(ctx, user)
```

We want to get only the documents that do not have the `deleted_at` field in them. We do this by defining the right filter when we get the data:

```
filter := bson.M{
		"_id": userID,
		"deleted_at": bson.M{
			"$exists": false,
		},
	}

err := r.collection().FindOne(ctx, filter).Decode(&user)
``` 

The key here is to add the `"$exists": false` condition to the filter, so we only get the records where this field does not exist.

So, to delete a document we just create the `deleted_at` field:

```
filter := bson.M{
		"_id": userID,
		"deleted_at": bson.M{
			"$exists": false,
		},
	}
	updater := bson.D{
		primitive.E{
			Key: "$set",
			Value: bson.D{
				primitive.E{
					Key:   "deleted_at",
					Value: time.Now(),
				},
			},
		},
	}

result, err := r.collection().UpdateOne(ctx, filter, updater)
```

So, that's it, not too hard, but it was kind of difficult to find a suitable approach for Go.

Hope you find this useful!

There's a fully functional example for this here:  [https://github.com/arielcr/soft-delete-mongodb-go](https://github.com/arielcr/soft-delete-mongodb-go) 
