Try RethinkDB in your browser
rethinkdb.com
rethinkdb.com
I didn't enjoy this experience one bit. It didn't feel interactive to me. Each step is basically "Run this query that is already typed out for you" without any explanation, whatsoever, about what each part of what I was writing was doing. This was followed by an invitation to click a link to documentation to try something else on the line of code you don't understand.
It begins with:
>r.db('test').tableCreate('tv_shows').run()
My first questions: what is r? What does db() do? Is there a test database somewhere? Why do I have to call run() when there's a button saying "Run this query"? Do you sometimes not run() things?
The tutorial doesn't remember your position if you go back to it so it's a good thing, I guess, that it opens a new tab for you when you access the documentation to list the tables.
Let's move to the second step:
>r.table('tv_shows').insert([{ name: 'Star Trek TNG', episodes: 178 }, { name: 'Battlestar Galactica', episodes: 75 }]).run()
Even more questions: What happened to r.db('test') that I needed to use? Is r now that database? Why didn't I just do r.tableCreate('tv_shows') before?
I did this with basically every step of the process but stopped just short of finishing because I wasn't learning much and wasn't sure where it was going. I found myself simply wondering what the heck RethinkDB was.
This tutorial could really use some more explanation, interaction, flow and direction. Tell me what I'm about to do. Tell me why what I'm about to do is worth my time and cool. Start with r, go from there. At least I won't be lost from the get-go.
Let me write stuff out as you're telling me what I'm doing. That's interacting.
To answer your questions here:
> what is r?
It's a module where all the RethinkDB operations are defined. The tutorial is running the same JavaScript driver code as you'd run if you connected to C++ RethinkDB server from node.js, which is why you have to start with `r`.
> What does db() do?
It refers to a database named 'test'. This is where you're creating the table
> Is there a test database somewhere?
Yes. It's set up by default at the beginning.
> Why do I have to call run() when there's a button saying "Run this query" do you sometimes not run() things?
Because you can type multiple queries in the text box. Every time you end a query with `.run()`, that's when it goes to the server and gets executed there. We've been talking about not having people type `.run` for a single query, but it's a bit difficult to solve.
> What happened to r.db('test') that I needed to use? Is r now that database?
If you omit r.db() at the beginning of the query, it picks a default one (which is 'test'). It's the same as you'd do in MySQL.
> Why didn't I just do r.tableCreate('tv_shows') before?
We thought allowing tableCreate in a default database allows people to make mistakes too easily, so we disallowed it. It confuses people, so we'll add it back. Sorry for confusion.
I have to confess: my initial reaction was "isn't this kind of self-explanatory" and "dude, if you want to know what rethinkdb is, look at their damned website" or even the dreaded, and admittedly elitist "if you have to ask, its not targeted at you." However, reading your response, I am reminded that I can be a smug asshole, and I'm going to remember how you responded for the day I release something to the public.
Your response, on top of the fact that I've already examined, installed, and liked your product, adds even more to my confidence that you guys are creating a great longer term product.
In studying a philosopher, the right attitude is neither reverence nor contempt, but first a kind of hypothetical sympathy, until it is possible to know what it feels like to believe in his theories, and only then a revival of the critical attitude, which should resemble, as far as possible, the state of mind of a person abandoning opinions which he hitherto held. Contempt interferes with the first part of this process, and reverence with the second.
This helped me a lot, hope it helps you too!
I'd recommend checking out TryRuby from Code School to get a better feel for interactivity in a tutorial. It takes you all the way from "That thing over there is an interactive prompt you are going to type things into."
Writing the code out yourself is extremely helpful for learning. Folks learn better by writing down what they are trying to understand while absorbing the information; the same is true for programming.
Edit: I totally see the value of the "hack it out yourself" flow he discusses though, and agree that making people do it themselves would be a more likely to be useful learning experience.
That said, it is also my opinion that the ORM syntax needs a bit of love, for all the reasons stated above. Especially .run() feels a bit weird, can you make queries lazy (like Django's QuerySets, which only run when evaluated)?
P.S. If the rest of the RethinkDB team are as good at DOTA 2 as Marc is, I want to play with you too!
In a way queries are lazy. You can write a query and without calling `run` on it nothing happens. The whole chained ops are executed at once when `run` is called.
> That said, it is also my opinion that the ORM syntax needs a bit of love, for all the reasons stated above.
This is not an "ORM" per se. It's a query API or data manipulation language. The next version will bring a few improvements to it.
That's not lazy, though, that's just doing nothing :P Lazy would be not running anything until you evaluated the last link in the chain, so, in Django:
model = User.objects
model = model.filter(name="Alex")
model = model.filter(hero="Dazzle")
model = model.filter(abandons<2)
list(model)
and the query would only be executed when wanting to turn the QuerySet into a list.I think your examples would also be a bit clearer if you forewent the r.db("test") step and just did:
db = r.db("test")
db.query("foo").bar().run()
which is more explicit.thanks,
alex @ rethinkdb
I actually think strict is better here, but that's a different discussion altogether :)
I don't see how it wouldn't be optimal, since lazy evaluation is a superset of eager evaluation (you can invoke it whenever you want).
Let me try to address some of these questions here, before figuring out how to improve the tutorial.
`r`: is the top level ReQL namespace that gives you access to the functions defined
r.db('name'): is accessing the 'test' database. RethinkDB supports multiple databases. You can specify which one to use on a per connection basis or for each query.
The 'test' database is a default database (in principle it's similar to MySQL's test database). Being the default also means that you don't need to use `.db('test')` in each query.
`run`: ReQL allows chaining multiple functions together. Basically creating a query is a bit like using a builder pattern. These chained ops are all sent to the server and executed on the database. There is a single roundtrip. Basically `run` tells the query builder: "now it's your time to do something for me".
As side comments
1. initially we added much more details about each query, but we ended up with quite a bit of text compared to short queries. We thought it would be more intuitive the reduce the description part and provide links to the API. It looks like that wasn't the best solution.
2. we chose to have the query pre-typed instead of having it part of the description only as we assumed mostly everyone would just copy paste it. Assumption proved incorrect!
Thanks a lot!
alex @ rethinkdb
In regards to your side comments:
1) If you feel like there's too much text compared to short queries, that's fine. I'm not there to write gigantic amounts of code. I'm there to learn and write a few little snippets to understand what I'm doing.
2) As I mentioned in my response to coffee, it's much better to actually type out the stuff as you go. It sinks in and immediately starts to develop a feel for writing in the language. Especially considering the non-traditional querying that you've come up with, I think it's very important to take baby steps and treat it as a new language. To continue along the language analogy: teach us each word so we know what the sentence actually says.
So take a careful look at Mongo and Redis tutorials. They made it feel easy, maybe why they got so popular.
Could also be that RethinkDB has fundamentally more complex syntax so not as suited to quickstart tutorials. When I did Mongo and Redis I didn't know SQL and didn't have to. With innerJoins everywhere you need SQL as prerequisite.
Not only that, but I found the documentation extremely lacking (almost nonexistent) when I was attempting to do the additional queries. When I was confused, there was nowhere to see the 'right answer' for the query and an explanation of why, I just had to guess at the syntax until I got it right.
How is:
> r.table('tv_shows').insert([{ name: 'Star Trek TNG', episodes: 178 }, { name: 'Battlestar Galactica', episodes: 75 }]).run()
Easier than:
> db['tv_shows'].push([{ name: 'Star Trek TNG', episodes: 178 }, { name: 'Battlestar Galactica', episodes: 75 }]);
Seems to me like a totally unnecessary abstraction which only adds complication and potential points of failure and bugs.
EDIT:
Ok never mind this does actually create a real database. From the demo it seemed like it was just creating a JSON object.
In the latter case you're creating a data structure in the host language (which of course is immensely useful, but completely different).
slava @ rethink -- I was responsible for the tutorial
As a side note, each programming language has its own idioms. We tried to bring the ReQL query to each language in a way that felt as close as possible to the host PL (as opposed to say SQL which you need to use it as it is; and that led to the hundreds or thousands of wrapper libraries/ORMs. etc).
alex @ rethinkdb
And also, probably I should better explore website, but is it transactional? In other words, is it possible to save multiple documents and RethinkDB server will reject them in case of conflict, just like all-or-nothing semantic in couchdb before ver. 0.9?
JSON docs are stored in tables -- a table is just a collection of JSON documents. We of course also support arrays, but the reason why we start with tables as a primitive is that it allows doing significant optimizations that otherwise would be very hard/impossible. If the entire DB was one huge JSON document, optimizations would be much more difficult to do. Grouping docs into tables essentially gives the system a hint as to the usage intent.
is it transactional?
Only for changes on a single document. There are no transactional guarantees on queries that touch more than one document.
Any plans to change it in future?
We've had lots of requests for more drivers and lots of offers to build them, but we've asked our volunteers to hold off while we revamp the driver interface to make it significantly easier to build drivers for RethinkDB. Having written the first JS driver myself and the new version I can attest to the much greater ease of doing so with the new API.
The next release (1.4) due very soon will include these changes and a driver development kit to support 3rd party efforts. After that I'm sure you'll see a PHP driver emerge very quickly.
For some reason reading through steps like "click here" makes me less comfortable than "type this".
Joe @ RethinkDB