Статьи

NoSQL на Android

Существуют различные решения NoSQL для мобильных платформ, таких как iOS и Android. Здесь мы рассмотрим Couchbase Lite (CBL — преемник TouchDB), легкую, полнофункциональную встроенную базу данных JSON.

Почему полнофункциональная база данных, а не просто оболочка для облачного сервиса? В основном, отзывчивость . Идея заключается в том, что приложение всегда должно быть доступно пользователям, даже если сеть не работает или работает медленно. Конечно, возможность работать с данными локально также означает, что в какой-то момент нам придется синхронизироваться с сервером.

Обратите внимание, что CBL значительно отличается от Apache CouchDB, несмотря на «Couch».

Теперь давайте приступим к делу и создадим небольшое приложение для Android (весь код доступен на GitHub ), которое настраивает базу данных с использованием собственного API CBL и выполняет основные операции CRUD.

Пройдя относительно простую настройку ( это для старых добрых пользователей Eclipse, а для поклонников Android Studio), давайте начнем с написания кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import com.couchbase.lite.*;
import com.couchbase.lite.android.AndroidContext;
 
/** Database wrapper*/
public class CbDatabase {
 
  private Database database;
  private Manager manager;
 
  /** Ctor Setup */
  public CbDatabase(String dbname)
                    throws IOException, CouchbaseLiteException {
       
     // 1. use default settings (read/write access)
     manager = new Manager( new AndroidContext(ctx), 
                            Manager.DEFAULT_OPTIONS );
 
     // 2. Check database name given by user
     // No upper case allowed in CBL!
     // Only the following characters are valid:
     // abcdefghijklmnopqrstuvwxyz0123456789_$()+-/
 
     if ( ! Manager.isValidDatabaseName(dbname)) {
         // report...
         return;
     
     // 3. Get existing db with that name
     // or create a new one if it doesn't exist
      database = manager.getDatabase(dbname);
  }
 
  //...more methods to come
}

Приведенный выше код использует Manager для настройки базы данных с допустимым именем. База данных CBL — это в основном контейнер для документов. Менеджер может создать несколько разных баз данных, каждая со своим собственным пространством имен. Вот как освободить все ресурсы:

1
2
3
4
5
6
/** */
public void close(){
  if(manager != null){
    manager.close();
  }
}

После того, как мы получили объект базы данных, мы теперь готовы выполнять над ним операции CRUD:

01
02
03
04
05
06
07
08
09
10
/** C-rud */
public String create( Map<String, Object> docContent )
                       throws CouchbaseLiteException {
 
  // create an empty document
  Document doc = database.createDocument();
  // add content to document and save it
  doc.putProperties(docContent);
  return doc.getId();
}

Документ CBL является основной сущностью, хранящейся в базе данных, и имеет следующие атрибуты:

  • Уникальный идентификатор (свойство _id), который может быть автоматически сгенерирован как UUID
  • Идентификатор ревизии (свойство _rev) для отслеживания обновлений
  • Набор пар ключ / значение, образующих тело документа

После создания мы можем получить содержимое документа по его идентификатору:

1
2
3
4
5
/** c-R-ud */
public Map<String, Object> retrieve(String docId){
  return database.getDocument(docId)
         .getProperties();
}

Мы можем обновить существующую запись пары ключ / значение в документе, используя обратный вызов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
/** cr-U-d (auto-retry) */
public void update( final String key, final Object value,
                    String docId )
                    throws CouchbaseLiteException {
 
   // retrieve the document from the database
   Document doc = database.getDocument(docId);
   doc.update(new Document.DocumentUpdater() {
       @Override
       /** This may be called more than once */
       public boolean update(UnsavedRevision newRevision) {
           Map<String, Object> properties = newRevision.getUserProperties();
           properties.put(key, value);
           newRevision.setUserProperties(properties);
           return true;
       }
   });
}

Метод автоматически повторяет обновление в случае конфликтов записи путем повторного чтения документа и повторного вызова метода обратного вызова. Этот процесс будет продолжаться, пока запись не будет успешной. Как следует из его названия, UnsavedRevision является изменяемой копией, с которой можно работать, пока данные не будут окончательно сохранены в базе данных.
Удалить документ довольно просто. Здесь мы делаем это по его идентификатору:

01
02
03
04
05
06
07
08
09
10
/** cru-D */
public boolean delete(String docId)
                      throws CouchbaseLiteException {
 
   // retrieve the document from the database
   Document doc = database.getDocument(docId);
   // delete the document
   doc.delete();
   return  doc.isDeleted();
}

Удаление документа создаст новую редакцию под названием «надгробная плита» (без шуток). Он будет помечен как удаленный, чтобы его состояние можно было реплицировать на сервер при выполнении синхронизации. Что касается обновлений, это может привести к конфликтам, если другие пользователи внесли изменения в тот же документ. В этом случае решение повторить удаление остается за нами.

Теперь мы готовы использовать этот класс-оболочку в нашем проекте. Во-первых, давайте определим наш вариант использования: допустим, нам нужно локально хранить некоторые пользовательские данные для наших мобильных игр, такие как электронная почта пользователя, когда пользователь зарегистрирован в нашей системе, и куча игровых очков. Вот быстрый тест, который мы можем запустить в методе onCreate () нашего основного Activity. Для начала давайте введем некоторые данные:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// get the current date and time
Date now = new Date();
String nowString = DateFormat.getDateTimeInstance(
DateFormat.LONG, DateFormat.LONG).format(now);
// game scores
List<Double> scores = new ArrayList<Double>();
scores.add(190.00);
scores.add(210.00);
scores.add(250.00);
scores.add(275.00);
// create an object that contains data for a document
Map<String, Object> docContent = new HashMap<String, Object>();
docContent.put("email", "[email protected]");
docContent.put("registered", nowString);
docContent.put("scores", scores);

Теперь операции с базой данных:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
try{
   CbDatabase db = new CbDatabase("testdb");
   // 1. Create
   String docId = db.create(docContent);
   // 2. Retrieve
   Map<String, Object> docContent = db.retrieve(docId);
   // 3. Update
   scores.add(350.00);
   db.update("scores", scores, docId);
   // 4. Delete
   boolean deleted = db.delete(docId);
   assert(deleted == true);
}
catch (Exception e) {
   // handle here...
}
finally{
  if(db != null){
     db.close();
  }
}

Вот соответствующие документы JSON для получения и обновления:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
// retrieved
{
  _rev=1-1ef4c4618a712cdf437d4b0c92594ddc,
  _id=69fdcb83-1774-4a3f-9e88-b298d3c7304a,
   scores=[190.0, 210.0, 250.0, 275.0],
   email=Nomad@nomad.com,
   registered=June 18, 2014 11:03:18 AM GMT+02:00
}
//--------------------------------------------
// updated scores: note the change in revision
{
  _rev=2-23e6d83d243f80c03b17c4160d511e16,
   scores=[190.0, 210.0, 250.0, 275.0, 350.0],
  _id=69fdcb83-1774-4a3f-9e88-b298d3c7304a,
   email=Nomad@nomad.com,
   registered=June 18, 2014 11:03:18 AM GMT+02:00
}

Вот и все. Более подробная информация о коде на GitHub . Мы просто поцарапали поверхность CBL с этим очень простым введением. К сожалению, онлайн-документация CBL для Android в настоящее время неполная, по сравнению с документацией для iOS. В любом случае, есть и другие важные функции CBL, такие как добавление вложений, представления и запросы, репликация (Server & P2P), REST API и т. Д. Это будут темы будущих статей.

Ссылка: NoSQL для Android от нашего партнера по JCG Тони Сицилиана в блоге Tony’s Blog .