Native
In this tutorial I'll create a database for the candy store to show the basic AnnaDB features.
Insert primitive
let's start with categories. Let's represent categories as simple string objects. To do so let's insert the first one into the categories
collection.
Request:
collection|categories|:insert[
s|sweets|,
];
collection|categories|
shows on which collection the query will be applied. In our case - categories
insert[...]
- is a query step. You can insert one or many objects using the insert
operation.
s|sweets|
- is the object to insert. In this case, it is a string primitive. Prefix s
means that it is a string, |
wrap the value of the primitive. Other primitive types could be found in the Data Types section.
Response:
result:ok[
response{
s|data|:ids[
categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
],
s|meta|:insert_meta{
s|count|:n|1|,
},
},
];
If everything is ok, in result will be returned ok[...]
vector with responses for all the transaction pipelines. Each response contains data
and meta
information. In our case there is only one response with a vector of ids
in data
and a number of inserted objects in meta
Insert container
Let's insert a more complicated object now - a chocolate bar. It will have fields:
- name
- price
- category
For the category, I'll use the already created one.
Request:
collection|products|:insert[
m{
s|name|:s|Tony's|,
s|price|:n|5.95|,
s|category|:categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
},
];
The query is similar to the previous one, but the object is not a primitive, but a map. The value of the category
field is a link, that was received after the previous insert.
Response:
result:ok[
response{
s|data|:ids[
products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|,
],
s|meta|:insert_meta{
s|count|:n|1|,
},
},
];
The response is nearly the same as before - link in data and number of inserted objects in meta.
Get object
Let's retrieve the information about this chocolate bar now. I'll use the get
operation for this, to the object by id
Request:
collection|products|:get[
products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|,
];
This time I use the get[...]
query step. Using this step you can retrieve one or many objects using object links.
Response:
result:ok[
response{
s|data|:objects{
products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
s|name|:s|Tony's|,
s|category|:s|sweets|,
s|price|:n|5.95|,
},
},
s|meta|:get_meta{
s|count|:n|1|,
},
},
];
In the response here you can see the objects{...}
map, where keys are links to objects and values are objects. objects{}
map keeps the order - it will return objects in the same order as they were requested in the get step, or as they were sorted by the sort step.
The category was fetched automatically and the value was returned.
Let's insert another chocolate bar there to have more objects in the collection:
collection|products|:insert[
m{
s|name|:s|Mars|,
s|price|:n|2|,
s|category|:categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
},
];
I use the same category id for this bar.
Modify primitive
Let's modify the category to make it more accurate.
Request:
collection|categories|:q[
get[
categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
],
update[
set{
root:s|chocolate|,
},
],
];
The query here consists of 2 steps. Get the object by link
step and modify this object
step. The update[...]
operation is a vector of update operators. Read more about the update.
Response:
result:ok[
response{
s|data|:ids[
categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
],
s|meta|:update_meta{
s|count|:n|1|,
},
},
];
The response of the update operation contains the ids of the updated objects as data and the number of the updated objects as meta.
Let's take a look, at how this affected the chocolate objects.
Request:
collection|products|:find[
];
To find objects I use the find[...]
operation. It is a vector of find operators. If it is empty, all the collection objects will be returned.
Response:
result:ok[
response{
s|data|:objects{
products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
s|category|:s|chocolate|,
s|price|:n|5.95|,
s|name|:s|Tony's|,
},
products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
s|name|:s|Mars|,
s|price|:n|2|,
s|category|:s|chocolate|,
},
},
s|meta|:find_meta{
s|count|:n|2|,
},
},
];
The category was changed for both products, as the category object was linked with these objects.
Modify container
Now I'll increase the price of the bars, where it is less than 2
Request:
collection|products|:q[
find[
lt{
value|price|:n|3|,
},
],
update[
inc{
value|price|:n|2|,
},
],
];
The find
step can stay before the update
step as well. All the found objects will be updated. Read more about find
operation and operators here.
Response:
result:ok[
response{
s|data|:ids[
products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|,
],
s|meta|:update_meta{
s|count|:n|1|,
},
},
];
The response is similar to the previous one.
Here is how all the products look like after update:
result:ok[
response{
s|data|:objects{
products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
s|name|:s|Tony's|,
s|category|:s|chocolate|,
s|price|:n|5.95|,
},
products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
s|category|:s|chocolate|,
s|name|:s|Mars|,
s|price|:n|4|,
},
},
s|meta|:find_meta{
s|count|:n|2|,
},
},
];
Sort objects
To sort objects I'll use the sort
operation against the price field
Request:
collection|products|:q[
find[
],
sort[
asc(value|price|),
],
];
The sort[...]
operation is a vector of sort operators - asc
and desc
. Sort operators are modifiers, that contain paths to the sorting value. The sort
operation is not an independent step, it can stay only after find-like operations, that return objects. You can read more about sort here
Response:
result:ok[
response{
s|data|:objects{
products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
s|price|:n|4|,
s|name|:s|Mars|,
s|category|:s|chocolate|,
},
products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
s|name|:s|Tony's|,
s|category|:s|chocolate|,
s|price|:n|5.95|,
},
},
s|meta|:find_meta{
s|count|:n|2|,
},
},
];
Objects in the response are sorted by price now.
It is useful to use limit
and offset
operations together with sort. You can read about them in the documentation
Make projections
To get only the name and price fields I'll use the project
operation
Request:
collection|products|:q[
find[
],
project{
s|name|:keep,
s|price|:keep,
},
];
The keep
operator is used to keep the value of the field or subfield in the output.
Response:
result:ok[
response{
s|data|:objects{
products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
s|price|:n|4|,
s|name|:s|Mars|,
},
},
s|meta|:find_meta{
s|count|:n|1|,
},
},
];
To set a new field with already existing value I use root
operator
Request:
collection|products|:q[
find[
],
project{
s|new_field|:value|category|,
},
];
Response:
result:ok[
response{
s|data|:objects{
products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
s|new_field|:s|chocolate|,
},
},
s|meta|:find_meta{
s|count|:n|1|,
},
},
];
It is possible to set any value to the field as well
Request:
collection|products|:q[
find[
],
project{
s|new_field|:s|new_value|,
},
];
Response:
result:ok[
response{
s|data|:objects{
products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
s|new_field|:s|new_value|,
},
},
s|meta|:find_meta{
s|count|:n|1|,
},
},
];
Delete objects
You can use delete
operation after any find-like step to delete all the found objects. Or it can be used independently to delete the whole collection.
Request:
collection|products|:q[
find[
gt{
value|price|:n|5|,
},
],
delete,
];
The delete
operation is a primitive without value.
Response:
result:ok[
response{
s|data|:ids[
products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|,
],
s|meta|:update_meta{
s|count|:n|1|,
},
},
];
The response contains affected ids in data
and the number of deleted objects in meta