MongoDB CRUD Queries from Java and Shell
Tags: mongodb, java, springboot, beginners
Published: 2020-08-31 13:44:56

In this tutorial you will see **working examples** for performing **CRUD operations** to a **MongoDB**. We will consider 3 clients:
* **MongoDB Shell** (supports JavaScript queries)
* **Java & Spring Boot**: typed access via MongoRepository
* **Java**: generic access via Documents / MongoCollection

![les pyramides d'euseigne](https://dev-to-uploads.s3.amazonaws.com/i/8u4p0yedhm83m0g826rx.jpeg)

# Installation of MongoDB Server and Client

First make sure you have access to a MongoDB instance. There’s a variety of MongoDB distributions, including production-grade servers and cloud-hosted solutions. For this tutorial, I recommend you keep things simple and install **MongoDB Community Server** and **MongoDB Compass** locally.

You can get the installation for the MongoDB server here: https://www.mongodb.com/try/download/community. During the installation setup, you’ll be asked whether you want to install MongoDB Compass. Make sure to uncheck that box since you might end up with a (stable but older) version of Compass which doesn’t support a built-in MongoDB Shell. Apart from this, you can just go with the standard settings and click your way through the whole installation procedure.

Then, follow through with the compass installation, which you can find here: https://www.mongodb.com/products/compass. Make sure to pick version **1.22 or higher**, this way you will get an integrated MongoDB Shell. After the installation, Compass will show the start screen. Just go with the default connection settings and hit “Connect”.

# CRUD Ops With MongoDB Shell

At the bottom of your Compass GUI, you’ll see the MongoDB Shell. We’ll start by looking up all available databases and creating our own `mydb` database:

```sh
> show databases
> use mydb
```

Now we’re ready to **create** our first documents:

```sh
> db.company.insertOne({name:"Amazon", marketCap:1600})
> db.company.insertOne({name:"Google", marketCap:1010, foundingYear:1998})
```

In MongoDB, we can create collections by simply adding a document to a collection. So above, we created the collection `company` implicitly. Let’s have a look at the content of our collection:

```sh
> db.company.find()
```

This will return Amazon and Google as JSON strings. Two things to note here:
* You can also view/edit/insert documents via Compass GUI
* MongoDB is schemaless. If you have a close look at the Google Document, you’ll see the company has an extra field `foundingYear`.

![MongoDB Compass GUI](https://dev-to-uploads.s3.amazonaws.com/i/9f9yxynutbi8et8c6c5u.PNG)

Alright, let’s fire our first advanced **read query**:
```sh
> db.company.find({marketCap:{$gt:1500}})
```

Here our [find](https://docs.mongodb.com/manual/reference/method/db.collection.find/) query uses `$gt` (greater than) and only returns Amazon. More [query filters]( https://docs.mongodb.com/manual/reference/operator/query-comparison/) are supported, like `$eq`, `$lt`, `$in`, etc.

Let’s consider one last read-query, which was pretty interesting for me, when I started using Document Databases:
```sh
> db.company.find({foundingYear:1998})
```

Here, we are searching for a company with founding year 1998. The fascinating point here is that not all companies contain this field, but MongoDB simply ignores companies without founding year.

Let's **change** an existing document:
```sh
> db.company.updateOne({name:"Google"},{$set:{name:"Alphabet"}})
```
The [updateOne](https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/) statement above searches for a company with the name “Google” and changes the name to “Alphabet”.

To wrap up this section, let’s **delete** a document:
```sh
> db.company.deleteOne({name:"Alphabet"})
```

# Typed DB Access with Java + Spring Boot

So far, we’ve looked at how to experiment with MongoDB using the MongoDB Shell as client. In a real application though, you’d do all interactions with the DB programmatically. Let’s jump into a **Java** example. In this section, we leverage the **MongoRepository** interface from **Spring Boot**. This way of accessing the database can be considered “**typed**”, as all data reads / writes have the same structure.

With [MongoRepository](https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/repository/MongoRepository.html), the “schema” of our documents need to be defined in the application code, so let’s go ahead and create a **POJO**:

```java
import org.springframework.data.annotation.Id;
public class Company {
  @Id
  public String _id;
  private String name;
  private Integer marketCap;
  // and constructor + setters + getters + toString method
}
```
Some uninteresting code lines are omitted for brevity. You can find all Java code with fully working examples on GitHub:
{% github pmgysel/mongodb-java-crud-ops no-readme %}

MongoRepository has a powerful feature: One can define an extending class, and Spring Boot will automatically create a bean which implements the repository.

```java
import org.springframework.data.mongodb.repository.MongoRepository;
public interface CompanyRepository
    extends MongoRepository<Company, String> {}
```

`CompanyRepository` will allow access to the `company` collection, and all documents from the DB will be represented as a `Company`. We’re ready to store our first companies:

```java
@Autowired
CompanyRepository repository;
Company amazon = new Company("Amazon", 1600);
Company google = new Company("Google", 1010);
repository.save(amazon);
repository.save(google);
repository.findAll()
    .forEach(System.out::println);
// result:
// Company{_id='5f48ff8bf557ca416e52a6c4', name='Amazon', marketCap=1600}
// Company{_id='5f48ff8bf557ca416e52a6c5', name='Google', marketCap=1010}
```

The way we interacted with the repository was via its [MongoRepository](https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/repository/MongoRepository.html) interface methods which include: `save`, `findAll`, `findById`, `delete`, etc.

Moreover, we can define additional **query methods** in our CompanyRepository. Let’s add a method to find a company by name and another method that searches by minimum marketCap:

```java
public interface CompanyRepository
    extends MongoRepository<Company, String> {
  List<Company> findByName(String name);
  List<Company> findByMarketCapGreaterThan(Integer marketCap);
}

// and then use the custom queries:
repository.findByName("Amazon");
repository.findByMarketCapGreaterThan(1500);
```

In order to **update** an existing document, you can first search for that company, use its setter methods to modify it, and then save it again:

```java
Company aCompany = repository.findByName("Google").get(0);
aCompany.setName("Alphabet");
repository.save(aCompany);
```

Finally, you can **delete** a company as follows:

```java
repository.deleteById(aCompany.get_id());
```

# Untyped DB Access with Java

Here we show a 3rd way for accessing the DB, in a totally **generic** and **schemaless** fashion. All access now happens through **Documents** which can hold arbitrary data. [MongoCollection](https://mongodb.github.io/mongo-java-driver/3.6/javadoc/?com/mongodb/client/MongoCollection.html) offers low-level access to the DB and we can dynamically look at fields inside a document and act accordingly.

Let’s start by initializing our **MongoCollection**:

```java
MongoClient client = MongoClients.create();
MongoDatabase db = client.getDatabase("mydb");
MongoCollection<Document> collection = db.getCollection("company");
```

**Persist** a document:

```java
Document google = new Document()
    .append("name", "Google")
    .append("marketCap", 1010);
collection.insertOne(google);
```

Note that the interface of MongoCollection only accepts `Documents`, which is basically a nested map of key-value pairs. Thanks to the dynamic content of a given Document, we can store any fields we want to.

For **read queries**, we can use `eq` (is equal):

````java
List<Document> google = new ArrayList<>();
collection.find(eq("name", "Google")).into(google);
google.forEach(System.out::println);
```

Many more query [Filters](https://mongodb.github.io/mongo-java-driver/3.6/javadoc/com/mongodb/client/model/Filters.html) are supported like `gt`, `lt`, `and`, `or`, `exists`, `ne`, etc. As a case in point, let’s search for companies which contain a field `marketCap` but don’t have the name “Google”:

```java
collection.find(and(exists("marketCap"), ne("name", "Google")))
```

Compared to the previous section, the query results aren't typed, we therefore need capability to **inspect** Documents:

```java
Optional<String> inspectDocument(Document document, String key) {
  return Optional.ofNullable(document.get(key))
      .map(Object::toString);
}
```

The above code snippet shows how to check whether a key exists and if so, serializes it into a String.

To wrap this tutorial up, here's how to **update** and **delete** a document:

```java
collection.updateOne(eq("name", "Google"), set("name", "Alphabet"));
collection.deleteOne(eq("name", "Alphabet"));
```

# Conclusion

We made it😀🥂 Now you know how to perform CRUD operations on a MongoDB from Java!

To sum up, MongoDB offers a powerful query language to manipulate documents of varying schema. for experimental purposes, you can use the MongoDB Shell. In this post, we focused on the Java client. Note though that MongoDB offers clients in pretty much every language, including JavaScript (Node.js), Python, and Go.

You can find all Java code with fully working examples on GitHub:

{% github pmgysel/mongodb-java-crud-ops no-readme %}

Let me know about your feedback / questions and leave a like❤️