It’s been a bit over three months since we released Dgraph v1.1.0 (see the announcement) but the wait and hard work were well worth it because today we announce that Dgraph v1.1.1 is released!
This blog post will cover the biggest changes since v1.1.0, including new features, bug fixes, and other improvements.
For those in a hurry, these are the changes covered in this article.
While this is not a patch release, to fix some of the issues identified with v1.1.0, we had to incorporate some tiny although breaking changes. This section covers both of them.
_reverse_
and _forward_
With Dgraph v1.1.0, the behavior of expand(_all_)
changed to include the predicates appearing in
the types associated with any of the nodes in the context. At that point, we realized that the
behavior of expand(_forward_)
and expand(_reverse_)
wasn’t well defined anymore.
We decided the best option was to remove it, after having published an announcement long ago on our discuss board.
Read below for a new way to expand nodes that might interest you.
@type
directiveIn our previous release, we added the possibility of tagging nodes with types thanks to the
<dgraph.type>
predicate and also added a function type(T)
, which returns true if the node in
the context has T
as one of its values in dgraph.type
.
All of this remains, but we also added a @type(T)
directive, which was simply an alias of
@filter(type(T))
. We realized that simplicity in the language was to be kept, so we decided to
simply remove it before it became a more well-spread feature.
Done with the bad news, let’s talk about what are the new things we are bringing to you with v1.1.1! Most of these features come as a result of listening to the amazing Dgraph community of users, thanks for helping us identify and prioritize improvement opportunities.
@cascade
and @normalize
anywhereUntil now, the @cascade and @normalize were only supported at the top query level.
With this latest version, you can use @normalize
or @cascade
at any other level, so you can now
perform queries such as the following.
{
roles(func: eq(name@en, "Jaws")) {
name@en
initial_release_date
starring (first: 5) @normalize {
performance.actor {
actor: name@en
}
performance.character {
character: name@en
}
}
}
}
The query fetches the name and release date for the movie Jaws and then, for five roles, it requests the role name and the actor that played it. Thanks to normalize, the role info is flattened into an array.
{
"data": {
"roles": [
{
"name@en": "Jaws",
"initial_release_date": "1975-06-20T00:00:00Z",
"starring": [
{
"actor": "Lee Fierro",
"character": "Mrs. Kintner"
},
{
"actor": "Chris Anastasio",
"character": "Out of Towner"
},
{
"actor": "Murray Hamilton",
"character": "Mayor Larry Vaughn"
},
{
"actor": "Christopher Sands",
"character": "Lifeguard"
},
{
"actor": "Beardsley Graham",
"character": "Mainlander"
}
]
}
]
}
}
We have removed some limitations existing in upsert blocks. The documentation has also been revamped and contains a bunch of examples.
With this new version, upsert blocks can have multiple mutation blocks that are executed in the order they appear. Thanks to this feature, we can remove the previous types assigned to a set of nodes and then set a new type.
upsert {
# Fetch all the nodes with a name predicate.
query {
people as p(func: has(name)) {
name
}
}
# Delete the previous values of dgraph.type if any.
mutation {
delete {
uid(people) <dgraph.type> * .
}
}
# Set dgraph.type to be Person.
mutation {
set {
uid(people) <dgraph.type> "Person" .
}
}
}
val
in upsert block mutationsThanks to this, you can now obtain not only the UIDs for a variable but also the values associated with them. One easy application is to be able to rename a predicate in a single upsert block.
upsert {
# First, fetch all the values.
query {
var(func: has(initial_release_date)) {
date as initial_release_date
}
}
# Then, delete the existing predicate.
mutation {
delete {
uid(date) <initial_release_date> * .
}
}
# Finally, create the new predicate with the same values.
mutation {
set {
uid(date) <release_date> val(date) .
}
}
}
In previous versions, it was impossible to know which UIDs had been impacted by an upsert. Only the new UIDs were reported in the response, but this has changed since v1.1.1.
In the query right above this paragraph, you can see that the query block is named var
, which is
how in Dgraph you request that block be omitted from the response. If you change that name to
something else (like q
), you will see the list of release dates appear in the response to your
upsert block.
Once you rename var
to q
, the response would look like the following:
{
"data": {
"code": "Success",
"message": "Done",
"queries": {
"q": [
{
"initial_release_date": "2005-09-01T00:00:00Z"
},
{
"initial_release_date": "1971-01-01T00:00:00Z"
},
...
],
"uids": {}
},
...
}
Types were added to Dgraph with v1.1.0, but since then we’ve identified some points that could easily be improved.
In v1.1.0, it was possible to provide a different type for a field in a type vs. the type of the predicate with the same name. This was a source of confusion, so we decided to simplify the type definitions to only have a field name, not a type.
To avoid a backward-incompatible change, we now simply ignore any type that might be given in the schema for any fields in a type after warning the user.
A simple schema defining two predicates and a type now looks like this:
<name>: string .
<age>: int .
type Person {
name
age
}
Some users in the community requested the capacity to expand the predicates declared in a given
type, rather than all of the types of the nodes in a given context as expand(_all_)
does.
We added the support for type names in expand
, so given the schema right above, defining the
Person
type, you can expand name
and age
by running the following query.
{
people(func: has(name)) {
expand(Person)
}
}
Notice that if some nodes had a name
predicate but were associated types other than Person
, the
behavior is different from using expand(_all_)
.
Facets are a very convenient way to attach information to a predicate rather than a node. For instance, you can store for how long a person has played an instrument with the following mutation:
{
set {
_:p <name> "Diggy" .
_:p <plays> "Drums" (since=2010-01-01) .
_:p <plays> "Piano" (since=2015-01-01) .
_:p <plays> "Violin" (since=2019-01-01) .
}
}
Some new things have been improved in the language since v1.1.0, and more improvements are coming soon!
You can fetch the instruments that Diggy has been playing since before 2016 with the following query.
{
q(func: has(plays)) {
name
plays @facets(lt(since, 2016-01-01))
}
}
Filtering on facets values was only possible with uid predicates before this version.
Let’s say you’d like to build a query that receives the year in the previous query as a variable.
In previous versions, this wouldn’t have been possible as GraphQL variables weren’t supported as
facet values.
GraphQL variables as facet values are now supported, but since the type date
is not supported
you’ll need to use a string.
query long_played($date: string = "2016-01-01") {
q(func: has(plays)) {
name
plays @facets(lt(since, $date))
}
}
Last, but definitely not least, our Enterprise users have now the possibility of encrypting their data at rest with Transparent Data Encryption. This new feature is part of our effort to improve Dgraph’s security standards for Enterprise users.
Enabling encryption is as simple as passing a flag --encryption_key_file
to your Dgraph Alpha nodes.
It is important to note that enabling encryption will not encrypt your existing dataset all at once.
Instead, new files will be encrypted - so as the compaction process for badger advances more of your
dataset will be encrypted.
If you wish to encrypt your whole database instead, you should:
As always, we want to thank the community for the amazing source of feedback and contributions. We wanted to give a shout-out to the eight amazing external contributors that got at least one commit in this release!
You can get the newest version of Dgraph already:
curl https://get.dgraph.io -sSf | bash
dgraph/dgraph:v1.1.1
and dgraph/standalone:v1.1.1