Приложения Delphi в Linux и доступ к базам данным MongoDB

АНДРЕЙ СОВЦОВ


Приложения Delphi в Linux и доступ к базам данным MongoDB

С выходом RAD Studio 10.2, включающей компилятор Delphi for Linux, появилась возможность создания на Delphi серверных нативных приложений для работы в среде Linux. Многие коммерческие и промышленные системы все чаще используют в качестве серверов вычислительные системы под управлением различных версий и редакций Linux - популярной, производительной и значительно более экономичной операционной системы широко распространенной на множестве облачных платформ и практически в любых центрах обработки данных. 

Многие Web-сайты и многозвенные приложения работают на Linux-серверах и обеспечивают одновременный доступ множества пользователей к хранимой на сервере или в распределенных системах информации, которая, в подавляющем числе случаев, хранится под управлением какой-то СУБД.

Библиотеки и компоненты Delphi для работы с базами данных позволяют быстро и в визуальном режиме создавать множество вариантов самостоятельных приложений, WEB- и REST-сервисов, встраиваемых модулей для промышленных WEB-серверов и серверов приложений, в том числе, Datasnap или RAD Server, активно работающие с любыми из обширного списка поддерживаемых СУБД.

За последние годы документо-ориентированная NoSQL СУБД MongoDB добилась огромной популярности и получила широкое распространение именно на серверах под управлением Linux. В силу особенностей Linux здесь MongoDB работает производительнее, лучше настраивается и масштабируется. 

На обзорных вебинарах и семинаре по RAD Studio 10.2 я уже показывал примеры реализации серверных приложений Linux, работающих с данными из MySQL. В самом простом случае нужно всего лишь добавить компонент TFDConnection, настроить его для связи с сервером БД, указав соответствующие параметры-свойства, а затем с помощью TFDQuery ввести нужный запрос и выполнить его. Остается только выдать\напечатать данные, полученные после выполнения запроса в нужной форме. Невероятно, но самым сложным является настройка драйверов доступа к СУБД, в данном случае MySQL.

Теперь я бы хотел рассказать, как реализовать простейшую программу для Linux-сервера, обрабатывающую данные из MongoDB. Несмотря на очевидную простоту реализации, стоит обратить внимание на характерные особенности работы с MongoDB.

Для этого примера я буду использовать установленный на моей VirtualBox VM с Ubuntu Server 16.04 отдельный сервер MongoDB v3.4. Как установить и настроить сервер MongoDB в Ubuntu Linux подробно описано в статье Установка InterBase и MongoDB в Linux (Ubuntu server) в этом блоге. Запуск демона MongoDB выполняется командой 

Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-78-generic x86_64)  * Documentation:  https://help.ubuntu.com  * Management:     https://landscape.canonical.com  * Support:        https://ubuntu.com/advantage Могут быть обновлены 0 пакетов. 0 обновлений касаются безопасности системы. asovtsov@ubuntu16srv:~$ sudo service mongod start [sudo] пароль для asovtsov: asovtsov@ubuntu16srv:~$

Кстати, для удобства переноса модулей в Ubuntu я пользуюсь утилитой WinSCP и PuTTY-терминалом для SSH-соединения с Linux.

В этом примере мы будем работать с базой данных из примеров работы с MongoDB в FireDAC , которые поставляются вместе с RAD Studio или Delphi 10.2. Это база данных (database) 'test' и коллекция 'restaurants', которая содержит более 25000 записей о Нью-Йоркских ресторанах, с привязкой по районам. Если ваш MongoDB на Linux еще не содержит такой базы данных, ее можно создать и заполнить прямо из Windows - открыть пример "C:\Users\Public\Documents\Embarcadero\Studio\19.0\Samples\Object Pascal\Database\FireDAC\Samples\DBMS Specific\MongoDB\Restaurants\Mongo_Restaurants.dproj", собрать и запустить его. Первая кнопка 'LoadData' создаст и заполнит нужную БД.

Для примера ограничимся только двумя запросами, зато интересными:

  • 'Count of restaurants grouped by borough' - подсчет количества ресторанов  в каждом районе
  • 'Count of Brazilian restaurants in Queens grouped by zip-code' - Подсчет количества ресторанов с бразильской кухней в районе Queens, с группировкой по почтовому индексу

Главный модуль приложения выглядит так:

program linuxMongo; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, uLinuxMongoDM in 'uLinuxMongoDM.pas' {fdm: TDataModule}; begin try { TODO -oUser -cConsole Main : Insert code here } AggregateData(); Readln; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. 

Вся магия работы с данными заключена в вызове процедуры AggregateData(); которая описана в стандартном TDatamodule в модуле uLinuxMongoDM.

Датамодуль устроен тоже достаточно просто, однако есть специфика работы с MongoDB.

unit uLinuxMongoDM; interface uses System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, FireDAC.UI.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MongoDB, FireDAC.Phys.MongoDBDef, System.Rtti, System.JSON.Types, System.JSON.Readers, System.JSON.BSON, System.JSON.Builders, FireDAC.Phys.MongoDBWrapper, FireDAC.ConsoleUI.Wait; const DBsrvAddr = '192.168.56.101'; type Tfdm = class(TDataModule) FDConnection1: TFDConnection; FDPhysMongoDriverLink1: TFDPhysMongoDriverLink; procedure DataModuleCreate(Sender: TObject); private { Private declarations } FEnv: TMongoEnv; FCon: TMongoConnection; procedure DumpCursor(ACrs: IMongoCursor; caption: string); public { Public declarations } procedure DataGetAggregates(); end; var fdm: Tfdm; procedure AggregateData(); implementation {%CLASSGROUP 'System.Classes.TPersistent'} {$R *.dfm} uses System.Diagnostics, FireDAC.Stan.Util; procedure AggregateData(); var DataModule1: Tfdm; begin DataModule1 := Tfdm.Create(nil); DataModule1.DataGetAggregates; DataModule1.Free; end; procedure Tfdm.DataGetAggregates; var oCrs: IMongoCursor; begin oCrs := FCon['test']['restaurants'].Aggregate().Group.Add('_id', '$borough') .BeginObject('count').Add('$sum', 1).EndObject.&End; DumpCursor(oCrs, 'Count of restaurants grouped by borough'); oCrs := FCon['test']['restaurants'].Aggregate().Match.Add('borough', 'Queens') .Add('cuisine', 'Brazilian').&End.Group.Add('_id', '$address.zipcode') .BeginObject('count').Add('$sum', 1).EndObject.&End; DumpCursor(oCrs,'Count of Brazilian restaurants in Queens grouped by zip-code'); end; procedure Tfdm.DataModuleCreate(Sender: TObject); begin with FDConnection1.Params do begin Clear; Add('DriverID=Mongo'); Add('Server='+DBsrvAddr); end; FDConnection1.Connected := True; FCon := TMongoConnection(FDConnection1.CliObj); FEnv := FCon.Env; end; procedure Tfdm.DumpCursor(ACrs: IMongoCursor; caption: string); begin Writeln(''); Writeln(caption); while ACrs.Next do Writeln(ACrs.Doc.AsJSON); end; end.

Вызываемая процедура AggregateData() управляет созданием и уничтожением объекта датамодуля. Обработчик его события OnCreate обеспечивает задание актуальных параметров соединения с сервером MongoDB, создает и инициализирует необходимые объекты (соединение и контекст) для работы с запросами и курсорами Mongodb. Сами запросы задаются и выполняются в процедуре Tfdm.DataGetAggregates, а процедура Tfdm.DumpCursor(ACrs: IMongoCursor; caption: string) обеспечивает выдачу заголовка запроса и полученных в результате его исполнения данных.

За исключением операторов консольной выдачи, исходный текст этого модуля не содержит изменений по сравнению с аналогичным для платформы Windows - фактически, это один и тот же код.

Укажем Linux64, как целевую платформу, и можно компилировать.

Чтобы Delphi автоматически переносил и запускал скомпилированный двоичный модуль, нужно в окне терминала Linux запустить PAServer, необходимый, кроме того, для выполнения отладки программ на Linux.

asovtsov@ubuntu16srv:~$ ~/PAServer-19.0/paserver Platform Assistant Server Version 10.0.1.23 Copyright (c) 2009-2017 Embarcadero Technologies, Inc. Connection Profile password : Starting Platform Assistant Server on port 64211 Type ? for available commands >

Если теперь собрать приложение и запустить его в Linux, то получим ошибку! Необходимо установить и настроить клиентские драйвера и библиотеки MongoDB.

В этом месте я совершил небольшую ошибку. Чтобы не повторять ее, рекомендую следовать указаниям документации: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Connect_to_MongoDB_Database_(FireDAC), раздел Client Software.

Дело в том, что работа FireDAC пока настроена на работу с драйвером mongoc от MongoDB версии 3.0. В состав дистрибутива Ubuntu 16.04 этот драйвер уже был включен. Моя ошибка заключалась в том, что я скачал, собрал и установил более современную версию драйвера 1.6.3. Переход на эту версию драйвера будет сделан в ближайшем обновлении (см. опубликованный RoadMap по RAD Studio). Пришлось "откатываться" на требуемый вариант.

Следуйте указанным в  документации инструкциям и выполните в окне терминала Linux:

sudo apt-get install libmongoc-1.0-0 sudo ln -s /usr/lib/x86_64-linux-gnu/libmongoc-1.0.so.0.0 /usr/lib/x86_64-linux-gnu/libmongoc-1.0.so sudo ln -s /usr/lib/x86_64-linux-gnu/libbson-1.0.so.0.0 /usr/lib/x86_64-linux-gnu/libbson-1.0.so

Вот теперь можно запускать проект на выполнение!

 


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=39283