Chapter 2. The ReQL Query Language

RethinkDB is queried using ReQL—a custom query language designed to be powerful and intuitive. ReQL provides a clear syntax that can be used to manipulate JSON documents in the database. This chapter will introduce you to the most common ReQL queries. More advanced use cases will be covered in the Chapter 4, Performance Tuning and Advanced Queries.

This chapter also covers the basics of moving data in and out of the database by creating tables and populating them with JSON documents.

In this chapter, you will learn the following:

  • Creating a database
  • Creating new tables
  • Adding, updating, and removing documents
  • Querying the database and manipulating results

Before we start querying the database, let's take a closer look at how a document database works, focusing on RethinkDB's data structure—JSON documents.

Documents

Documents are RethinkDB's main data structure. To fully understand and use the database, you need to think in documents. In this chapter, we're going to go through the lifecycle of designing and saving a document in RethinkDB. We'll follow up by reading, aggregating, and querying documents using ReQL. In the previous section, you'll see how RethinkDB can also manipulate and transform query results.

Documents are self-contained units of data. In relational databases, you might have heard the term record to describe something similar. When you insert some information into a database, the data is usually made up of small native types such as integers and strings. Documents are the first level of abstraction over these native types. They give primitive data some structure and logically group it. Additionally, RethinkDB documents support more complex data types such as binary data, dates and times, and arrays.

Suppose we want to store the age of a person in the database. This data might be encoded as an integer (24). However, this number is usually a part of a more advanced structure that contains a label as the following one:

"age": 24

And related data, such as the name of a person. An example of this structure is as follows:

{
"name": "Alex",
"surname": "Wilson",
"age": 24,
}

In RethinkDB, documents are stored in tables, which can be defined as a collection of documents. Tables, in turn, are stored within databases, which are the collections of tables. The number of documents that you add to a database table depends on your application and use case, but generally, RethinkDB does not have a hard limit on the number of databases, tables, and documents that you can create.

Document databases

Just as with records in relational databases, documents also support CRUD operations (Create, Read, Update, and Delete) that let you interact with the database. You've already learned that RethinkDB uses the JSON data format to store documents, so now, let's see how the database saves this data at a lower level.

Each document in the database has a unique primary key called an ID, which is unique per table. RethinkDB gives you the freedom to use any string to be the ID; however, it is recommended to use a UUID (Universal Unique Identifier).

Note

UUIDs are random numbers that have an extremely low collision probability. It is such that everybody can generate thousands of UUIDs a minute for millions of years without ever creating a duplicate. This is a great way to ensure that two independent users working on the database cannot insert two different documents with the same ID.

If you don't have a UUID, you can ask RethinkDB to make one for you; in fact, by default, if you do not provide a value for the primary key, RethinkDB will randomly generate one and add it to the document under the ID attribute. A document's ID is extremely useful as it allows us to uniquely refer to a specific document in a table. For this reason, retrieving documents by their primary key is very efficient and since ID's are unique, we are guaranteed to receive a single document as the query result.

JSON document format

RethinkDB uses JSON to represent data—a lightweight, data-interchange format based on the JavaScript syntax. One of its best features is that JSON is much easier for humans to read and write in comparison to other formats such as XML. We can parse JSON easily with JavaScript because it shares the same syntax. This is actually very convenient when we build dynamic web applications in JavaScript or Node, and we want to exchange some data between the client and server.

The first step in designing a database-based application is deciding on the format that it will use to represent and store data. JSON gives us the freedom to structure our data in the way we want without the need of defining a schema or deciding on the structure beforehand. This is an incredible time-saving feature, as often, the requirements of data objects keep changing all the time during development, and a JSON document is essentially a document.

In the following sections, we will take a closer look at how to structure a JSON document.

Keys

The keys in a JSON document are strings. Any Unicode character is allowed in a key with two exceptions as follows:

  • A key must not contain the null character () as this character is used to signify the end of a key
  • The . and $ characters should be considered reserved; programming languages drivers would complain if they are used inappropriately

RethinkDB is also type and case sensitive so, for example, these documents are considered distinct:

{"age": 20}
{"age": "20"}

As are these:

{"age": 20}
{"Age": 20}

A final thing to note is that documents inserted in RethinkDB cannot contain duplicate keys. For example, the following is not a valid document:

    {"message": "Hello, world!", "message" : "Hello from RethinkDB!"}

Arrays

Arrays are ordered lists that can contain zero or more values. Each of these can be of any data type. Arrays are extremely useful as they can be used for both ordered (lists, stacks, or queues) and unordered operations (sets).

In the following example, the key people has an array value:

{
  "people":[
    {
      "name":"Alex",
      "age":23
    },
    {
      "name":"Greta",
      "age":15
    },
    2
  ]
}

As we can see from the preceding example, arrays can contain different data types as values. In this case, the array contains two objects and a number. In fact, array values can be of any kind of the supported values including embedded arrays.

The ReQL query language makes working with complex documents really easy as RethinkDB understands the document structure and, in this example, it can reach inside the arrays to perform operations such as searching or indexing the content:

r.table("users").filter(r.row("people")("name").eq("Greta")

For instance, the previous query will instruct RethinkDB to query for all the documents where the people array contains a name field with the value Greta.

Embedded documents

Documents (that is, objects) can also be used as the key's value, and this is called an embedded document. Embedded documents can be used to structure data in a more organized way than just a simple list of key-value pairs.

For example, if we have a document representing a person and want to store his/her address, you may be tempted to simply store it in a string as this:

{
  "name":"Alex",
  "address":"23, St. John's Street, London, EC1V4PY"
}

What if we later want to access just the postcode? We can organize this information in a more structured manner by storing the address in an embedded address document:

{
  "name":"Alex",
  "address":{
    "street":"23, St. John's Street",
    "city":"London",
    "postcode":"EC1V4PY"
  }
}

The value for the address key in the previous example is an embedded object with its own key/value pairs for street, city, and postcode. As with arrays, RethinkDB understands the structure of embedded objects and is able to reach inside them to perform queries.

As an example, let's insert the previously defined document into RethinkDB:

r.db('test').table('people').insert({
  "name": "Alex",
  "age" : 24,
  "address": {
    "street": "23, St. John's Street",
    "city": "London",
    "postcode": "EC1V4PY"
  }
})

Organizing the data in this way allows us to directly access the postcode with just one query:

r.db("test").table("users")("address")("postcode")

Data modeling

Now that we know all about how to structure a JSON document, let's go through building a full-fledged example to show you in practice how to work with documents. We will use this example in the following sections where we will add this data to the database and then query it.

Let's draft a JSON format for friends, their contact info, and their interests. We know that each document will have a name, surname, year of birth, address, e-mail, and interests. It should be pretty straightforward to model this data as most of it will be a list of key/value pairs with the only exceptions being the address and interests. As we have seen in the previous section, we can structure the address in a more organized way using embedded documents, so we will be doing this. Lastly, interests will be contained in an array.

The following example shows a document that meets our requirements:

{
  "name":"Alex",
  "surname":"Jones",
  "age": 24,
  "email":"[email protected]",
  "address":{
    "street":"23, St. John's Street",
    "city":"London",
    "postcode":"EC1V4PY"
  },
  "interests":[
    "programming",
    "football",
    "cars"
  ]
}

You can see that the general structure is based around key/value pairs and lists of interests. This example contains various data types: strings, numbers, embedded objects, and arrays. The cool thing is that we just made up this example on the spot. It didn't require defining a schema, and we didn't have to define how the data should look. We just created a JSON document with all the data that we needed.

Now that we have an example document that we can work with, it's time to start querying RethinkDB! We will start by adding data to the database.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.218.105