Use mongo-cl-driver as a provider of the database mongo on common-lisp





Hello, all lovers of common-lisp.

In this article I will tell you about their experience in the implementation of common-lisp library access object database management system mongo called mongo-cl-driver.

After reading online about how mongo-db a fast, scalable and cool and distant and having a very poor experience with this DB in C++, I decided to try this database in its web-oriented project written in common lisp. Having, however, some doubts about the choice of DBMS, you can call your experience successfully accomplished, because the implemented functionality at least works.

Any person who begins to program access to the database mongo somehow stumbles on the Internet at links cl-mongo — and the second largest provider of access to the database mongo on common-lisp. Using cl-mongo in my project, I came across a number of problems with conversion of data into json, which began when the need arose to transfer the results of the query along the chain DBMS->common-lisp-server->javascript client. By the way for such encoding/decoding, there are libraries known to me:

1) yasson
2) cl-json

Hereafter follows some examples of using the mongo-cl-driver for General programming problems of access to the database mongo on common-lisp. If examples seem to the reader obscure, torn out of context, it is possible to see the examples of use are available source code. The most valuable pieces of code contained in the file webserver.lisp and competitions.lisp

In General, let's take this bull by the horns:

Connection and access to the database can be divided into two steps: creating an instance of the database class and an instance of the collection class. Further — very convenient to work with the collection instance.

Create an instance of the CLOS class database. On object-oriented programming in common-lisp you can read the translation of the book practical common lisp. This constructor can also take arguments host, port, user and password, however, the author used only the first two parameters.

Create a database instance for database access called ski73:

the
(defparameter *db-instance* (make-instance 'mongo:database :name "ski73"))


To work with the specific collection, you must create an instance of the collection class:

the
(defparameter *competitions* (mongo:collection *db-instance* "competitions"))

Now we can use it in our project.

To fetch the required information, you can use one of the additions to the mongo-cl-driver functions: find-one or find-list. For a start, is invited to submit what it looks like in the console mongo query to fetch the names and dates of the competitions in the competitions of the collection:

the
db.competitions.find({}, {title: 1, date: 1});


To select all fields in the document, you need to call find with no parameters:

the
db.competitions.find();


As the first member function find transmitted conditions of the sample. Similarly, we specify the where clause in the SQL query. The second parameter is the filter voznesenya values we specify we are interested in the names of the target fields, marking them 1-kami. For more information you can refer to documentation on mongo queries.

In mong-cl-driver receiving a list of documents is implemented through the find function-list and sampled one document — using find-one. Unfortunately, neither method can not (from the subjective experience of the author) to support the query and filter parameters by default. Here is the list of competitions from the collection of competitions.

the
(find-list *competitions* :query (son) :fields (son "title" 1 "date" 1))

In order to exclude from the sample any filters and search terms, you need to pass as parameter values :query and fields calls son without any parameters.

Here's an example:

the
(find-list *competitions* :query (son) :fields (son))


To search a single document, use the function find-one. As the first (filter) and a second (mask) settings it also needs to tell you if the request is made without conditions and filters, empty calls son

For example:

the
(find-one *coll-instance* (son) (son))


What is son?

In order for the find request in the common-lisp performed in the same manner as is done in the mongo console, you need to pass in two structures with a set of key-value values. By the way, in the same cl-mongo have a similar feature that and it's called the kv (key-value). I can't remember exactly, but there are with her, along with other functions, some inconvenience.

In mongo-cl-driver is a function of son.

That invented on the go an example of constructing a query with a non-empty query parameters and fields:

the
(find-list *coll-instance* :query (son "name" "Ivan" "surname" "Ivanov")
:fields (son "name", 1 "surname" 1 "address" 1 "telephone"))


In the even positions are functions of the target key (the names of the members) on an odd value.

It follows, then, is a simple example of a method of producing key-value object class representing a sporting event.

the
(defmethod mongo-doc ((c-instance competition))
(son "title" (title c-instance)
"date" (date c-instance)
"begin-time" (begin-time c-instance)
"end-time" (end-time c-instance)
"captions" (captions c-instance)
))


Search by Id

A related objective in the development of client-server http application was transfer to the server id ka obtained previously — the previous request from the client. Perhaps the approach is not entirely correct, but I decided that id need to transfer the whole piece. The following example will help to clarify the situation.

Imagine that our database stores objects of the competition and each has nested lists of races (rounds)

Here is a list of all competitions to be sent to the client as json. The answer is formed in the context Manager server http hunchentoot. define-url-fn is a macro that creates and registers the handler function for the query competitions-list, for example this ski73.ru:4242/competitons-list. Convenient, right?

the
;List of triples {id, title, date} to pass a list of competitions
(define-url-fn (competitions list)
(str (encode-json-to-string (find-list *competitions* :query (son) :fields (son "title" 1 "date" 1)))) )

In this example, we register the request handler to receive a list of competitions. We are interested in the name and date. find-list will always return for each retrieved document and its 12-byte id scnic together with the specified parameter :fields fields. On client side javascript a it is stored in an array of 12 Number-s. It was decided to deserializedate him in line to submit another request to the server, which would receive a more capacious structure with information on races with konkretnymi results athletes.

Function mongoId designed to convert array of numbers into a string made up of bytes of the identifier in accordance with the contents of the 12-element array mid.

the
/** Get the row which contains 12 bytes mongo id person to transfer the request */
function mongoId(mid) {
var strId = new String();
var plusByCode = function(el, index, arr) {
return strId += String.fromCharCode(el);
};
mid.raw.forEach(plusByCode);
return strId;
}


Obtained using mongoId string we put in a POST request. And then on the server side, request information on this id-shnik of mongo-db. Here's how:

the
;for further information on the competition
(define-url-fn (competition-info)
(let ((id (post-parameter "id")) )
(str
(encode-json-to-string (find-one *competitions* 
(son "_id" (make-instance 'object-id :raw (flexi-streams:string-to-octets id))) 
(son of "rounds" 1 "captions" 1 "title" 1)))
)))


A key point in the design of the query is a function of obtaining a 12-element vector of numbers from the string passed to the client c in the form POST parameter — flexi-streams:string-to-octets. The resulting vector is placed in the constructor of a class object-id.
So in conclusion, for those who want to try to be less of curses towards the author provides a very brief description of the installation process mongo-cl-driver Wednesday common-lisp. Practically, the implementation of sbcl.

When you install the mongo-cl-driver in novice lisp programmers, which the author also considers itself a part, can occur seemingly insurmountable problems.
Installed mongo-cl-driver with such a simple spell:
(ql:quickload "mongo-cl-driver")
In your Lisp environment, by this time, must be configured with a quick-lisp — system for downloading and installing lisp programs. On the official website of the project can read it and poyuzat — www.quicklisp.org/beta
Most likely, in the middle of the installation process will come out the exception (restart), an error message, broadcasts the fact that there are unresolved dependency — cl-camel-case.
Take it the author mongo-cl-driver and install using one of three methods described on a remarkable site lisper.ru (beautiful lizards), section wiki
I hope nothing is lost. I will only add that the library used to create the author's resource for skiers. Available source

Special thanks to the author mongo-cl-driver archimag- for some hints during the development of the resource. And good luck, friends!
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

When the basin is small, or it's time to choose VPS server

Performance comparison of hierarchical models, Django and PostgreSQL

From Tomsk to Silicon Valley and Back