Hello. I'll be introducing Voyage, a wrapper for NoSQL databases,
in this class.
The goal is to let you build a real application.
You'll be able to store objects like TinyBlog with Voyage,
in a Mongo database, and deploy on a real service.
I also wanted to show you
an easy way to store objects.
Voyage is a simple solution.
First, what is MongoDB?
Mongo is a new document-oriented NoSQL database.
It features a powerful query language.
Mongo is also one of the most popular DBs, with CouchDB and Riak.
We'll be using Mongo and Voyage.
Actually, Voyage is a mapper. It takes objects and maps them
on MongoDB, almost automatically, for the programmer.
If you've done Java on Hibernate
Voyage is the equivalent of Hibernate for MongoDB.
And it's made for Pharo.
Here are Voyage's features. It's very simple.
It ensures object identity when you reload them.
It provides error-handling.
And it also implements a connection pool
to speed things up.
To start simple, the first thing we'll do
is create a MongoRepository.
It uses these expressions:
You want to access your Mongo database,
which is managed from outside Pharo.
Often, when we are in prototype mode,
we use a Mongo database in the memory.
It's referred to here as Mongo Memory Repository.
You don't need a Mongo database. First, you prototype your application.
When it is running right, you switch the memory repository
into a real repository, and tackle your outside DB.
That's the way to proceed.
To illustrate Mongo,
we have a simple model of superheroes with superpowers,
their armor and weapons.
You'll be able to do the exercise based on what I show you in the course.
This is the support.
I think you'll enjoy scripting Superman.
First, let's look at how Hero and Power operate.
Basically, we have a Hero class, with a name, level, and powers.
I have an accessory for the name, a setter for the name.
Same for the level, here.
And I manage the powers as a set.
If powers is empty, I put in a set.
When I can add a power, I add one to the set.
So it's really very basic.
For the moment, the powers only have a name.
You can write the name or not.
Now, the point is to find a way to declare
that my domain classes are stored in a database.
The root class idea gives us an entry point for our database.
It can be any class in the system, and it is marked as the root
with a class method (I emphasize class) called isVoyageRoot.
This is how we do it for Hero class: isVoyageRoot returns true.
At this point, Voyage knows I will be able to store my heroes
in the Mongo database.
Let's do Spiderman.
His name is Spiderman, his level is epic.
His powers are his super strength, his ability to climb walls,
and the spider instincts he is purported to have.
I save that information.
"Save" tells Voyage to take this superhero,
and store it in the base.
We do the same thing with Wolverine and his powers,
and save that data.
Now, if I look at my Mongo base,
using db.Hero.find,
I see my hero Spiderman,
and I should see his powers.
This is where you have to be careful.
His superpowers are described in full here.
Same for Wolverine, etc.
Once you've done that, you can do lots with Pharo.
I won't go into the details. But I can select all the superheroes...
That gives me Spiderman and Wolverine.
I can say find Spiderman...
I can say I want to find all superheroes who have an epic level.
That gives me my two superheroes.
I can also express it differently.
Actually, the Mongo database
understands Json, so I can create Json on the fly,
inject it, and do Json-based queries.
Let's say I want to know
which superhero is named Spiderman.
But I've expressed it in Json form, as dictionary, so it returns an entry.
I can do the same thing with "select Many."
It depends on the easiest way for expressing your query.
But that's a detail for you, right now.
You can do much more advanced queries.
I can say "select all" the heroes
or "many" of the superheroes with an epic level.
I can sort their names in ascending order.
I set a limit of 10, and say I want to start at page 0.
That will bring me sections of the database.
When you need that, look in the documentation.
We can do other operations, like count our superheroes.
I can count those whose possess a certain property.
I can remove some. If I remove all, I empty the database.
Be careful of that command.
Here, I can select one, and remove it.
That hero will be removed from the base.
These are all operations that make sense.
Now, the question that will arise when using MongoDB
is, what is the base root, in Mongo lingo?
When is a class defined as a root?
The answer is, if you want to query that class.
That's the first rule.
I define that class as a root,
because I want to have access to all the objects in the class.
The other reason is wanting to be able to share
these objects between roots.
Say I want to share powers, to make it clearer.
I want to be able to share powers between heroes.
In that case, I have to define power as a root.
Watch this.
In our example, hero is a root.
But power can also be a root.
In Voyage, you can declare any class as a root.
Here is how to do it.
I say Power class isVoyageRoot.
Now, if I create the power "Fly,"
and save it, it is in the base.
Superstrength? The same.
Now I'll be able to make a query
that tells Voyage to get the power to fly.
I also want Voyage to get the power of superhuman strength.
And now I recreate Superman.
I say, "Hey!
I got these two powers, so there's only one in the system, and I save it.
But it's important for me to reset the base
so that it works right,
whenever you change the basic schema.
But now I want to show you what I have now.
Superman's powers are described differently.
The power isn't composed inside. I have a reference to a power.
That means if I have another superhero who knows how to fly,
I can share that superpower, instead of having two instances.
So, depending on your domain and how you want to modelize it,
you'll define roots differently.
This silly example is just to give you an idea.
Actually, if I repeat myself, you define a domain root
if you want to query it or share objects in the root.
In Voyage, relationships are expressed
the way "foreign keys" are in relational databases.
Voyage automatically handles cyclic references of root objects.
But be careful: Voyage does not support cyclic references
between embedded objects.
You'll experiment, and see. If you have roots, you're home safe.
In this course, I wanted to show you how easy it is to store objects
in a Mongo database.
If you want to know more, look at Enterprise Pharo: a Web Perspective.
It's in the MOOC resources.
You can also refer to a little tutorial on building the superhero base.
You can learn it all.