Living The Life

Living The Life

Thursday, May 25, 2017

MongoDB and Spring Boot - Easy as a Dream

I have a long history with SQL databases.  I've almost been tempted to write a basic one from scratch a few times for the fun of it.  But I haven't worked with a NoSQL database before.  With it raining outside, this seemed like a great day to give one a try.  Thus, I started looking into MongoDB.  I was prepared for this to take awhile, but this was like a dream.  I think I spent more time writing this blog post than it took to get going.


Step 1: Install MongoDB

I was wondering how hard it would be to install MongoDB on my Ubuntu home computer.  I wondered if it'd already be packaged for Ubuntu, if there'd be issues with dependencies, or etc.  But guess what?  There's a free online version, no install needed.  Since I want to learn more about the language and using it than how to install, I went with that option.

https://www.mongodb.com/cloud/atlas?jmp=download-center

Note, the next page after that looks like there's a cost, because it defaults into one of the premium selections.  Change the option back to the free one and it is really free.  And overall, just walk through the wizard on creating it and setting it up.  You don't configure any data or schema here, just basic instance config, and 1 admin user for the instance.

Step 2: Use Spring Boot

I figure I'm most likely to really use MongoDB with a Java Spring Boot application.  I wondered what Spring Boot might have in the way of MongoDB support.  Again, I prepared for the worst in my mind.  But again, it turned out to be crazy easy.

There's a good starter application walk through guide here: Accessing Data with MongoDB

The only thing I had to customize from the document was specifying a remote MongoDB instance.  The guide assumes you are running MongoDB locally.

  1. On the free MongoDB install web page, go to Clusters and then click the "Connect" button.
  2. A pop-up will come up.  On that screen, there's a "URI Connection String" that starts with mongodb://.  Save that URI.
  3. In your java codebase, add an "application.properties" file into the classpath, such as in "src/main/resources/".
  4. Open the properties file and specify the property spring.data.mongodb.uri to have the URI Connection String from the web site.  Thus, something like: spring.data.mongodb.uri=mongodb://USER:PASSWORD@cluster....

Then run the example and it will connect and work as documented on the web page.

This was so simple, like a dream simple.  Maybe it is too simple, I didn't learn anything about MongoDB, which kind of shows the power and usefulness.  Developers can work with simple POJO objects and not really have to go learn much about MongoDB at least for the basics.

Step 3: More Advanced Guide

Spring boot has a slightly more advanced guide: Accessing MongoDB Data with REST

Again, you need to have the application.properties with the mongodb URI if using it remotely.  And you can just bolt-on to the earlier Customer guide instead of creating a new Person.  Save some time.

Again, amazed at how easy this was.  I had an object backed to a MongoDB with full featured REST API over top of it.  Again, as easy as a dream.

One tip on using curl, the guide shows using curl to post new entries with a -d command line option.  That works, but it is annoying to escape a JSON string on a linux command line.  The -d (data) option support a file as an input if you just identify it with "-d @fileName"  Example:

curl -i -X POST -H "Content-Type:application/json" -d @frodo-person.json http://localhost:8080/customer

And with the frodo-person.json looking like:
{
  "firstName" : "Frodo",
  "lastName" : "Baggins"
}

Step 4: Trying to Make It Hard

Adding More Columns

I added a few more properties to the Customer class.  Inserted new rows with those set.  The new objects work as expected, and the old object results come back as NULL for those newer properties.

Find By Last Name Case Insensitive

Again this is so easy that I need to make it harder to learn something about MongoDB.  The search by last name is case senstive, so I figure trying to make a case insenstive search should be interesting.  Alas, that's easy too.

In the CustomerRepository, add a new method:
public List<Customer> findByLastNameIgnoreCase(@Param("lastName") String lastName);

And now you have a last name search that is case insensitive.

Take a look through the Spring Data MongoDB - Reference Documentation in query creation section.  It has even more advanced examples.  Again, no special knowledge of MongoDB needed.

Manual Query with Annotation

The built-in find can probably do everything I'll need day to day, but I just had to dig under the covers to do a "manual" query.  That was easy too:

In the CustomerRepostiroy, which I did a @RepositoryRestResource on, add a method:
@org.springframework.data.mongodb.repository.Query("{'lastName':{'$regex':?0}}")
public List<Customer> findByName(@Param("searchText") String searchText);

Then you can hit this endpoint
curl http://localhost:8080/customer/search/findByName?searchText=mit

And get back the 2 example Smith results.

You can even make it case insensitive:
@org.springframework.data.mongodb.repository.Query("{'lastName':{'$regex':?0, '$options':'i'}}")
public List<Customer> findByName(@Param("searchText") String searchText);

Or, you can even make it search either first or last name:
@org.springframework.data.mongodb.repository.Query("{'$or':[{'firstName':{'$regex':?0, '$options':'i'}},{'lastName':{'$regex':?0, '$options':'i'}}]}")
public List<Customer> findByName(@Param("searchText") String searchText);

See the MongoDB docs for the query language

Manual Query with Query Objects

The annotation probably covers even more of the possible use cases, but there's more.  There is a Query object you can use to construct queries.

In the CustomerRepository, add a method:
public List<Customer> findAll(org.springframework.data.mongodb.core.query.Query query);

Note, this Query is in a different package, which is why I've fully typed the Query references on this post.

Then in your app run code:
List<Customer> results = repository.findAll( new Query(where("lastName").is("Smith")) );

Or slightly more complicated, a case insensitive regular expression search:
List<Customer> results = repository.findAll( new Query(where("lastName").regex("s.*h","i") ) );

That's it.  Again, amazing how easy that all is.

Going Beyond

  1. Spring Data MongoDB - Reference Documentation
  2. Spring Data MongoDB - API Docs
  3. MongoDB Documentation
  4. Mongo Shell - Run directly against a MongoDB from a web page, interesting in its own right


No comments:

Post a Comment