Couchbase Lite機能解説：JSONデータ操作

## はじめに


以下のドキュメントの内容をベースに、ドキュメント指向NoSQL組み込みデータベースCouchbase Liteを用いたAndroidアプリ開発におけるJSONデータ操作について、具体的なコードを交えて解説します。

https://docs.couchbase.com/couchbase-lite/3.0/android/document.html

なお、Couchbase Liteについては、[Couchbase Mobileアプリケーション開発へのロードマップ](https://qiita.com/yoshiyuki_kono/items/6a5bbad1b02196a25417)に記事をまとめている他、（これらの記事を元に構成した）以下の電子書籍を無償で頒布しています。

https://techbookfest.org/product/5074954942939136?productVariantID=5042865933647872

また、Couchbase Serverの存在意義、機能詳細、利用方法等については、拙著[NoSQLドキュメント指向データベースCouchbase Serverファーストステップガイド(インプレスR&D刊)](https://www.amazon.co.jp/-/en/%E6%B2%B3%E9%87%8E-%E6%B3%B0%E5%B9%B8/dp/429560030X/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=1636588872&sr=1-1)や、[NoSQL/JSONデータベースCouchbase Server理解・活用へのロードマップ](https://qiita.com/yoshiyuki_kono/items/4c9cd1115efc5807b49f)にまとめてある記事をご参考ください。

## JSONデータ操作




### ドキュメント

Couchbase Liteでは、`Document`とJSON文字列との間の変換がサポートされています。

#### JSON文字列への変換

`Document`の`toJSON()`メソッドを使用して、JSON文字列を取り出すことができます。


``java
final String json = database.getDocument(docId).toJSON(); 
```

#### JSON文字列によるドキュメント作成
JSON文字列を使用して`MutableDocument`を初期化することができます。

```java
final MutableDocument document = new MutableDocument(docId, json);
```


#### 実装サンプル


下記の例では、まず、データベースからドキュメントをJSON文字列として取得し（①）、そのJSON文字列を使用して`MutableDocument`を初期化し、別のデータベースに保存しています（②）。最後に、JSONから作成されたドキュメントを取得し、値を出力しています（③）。


```Java
final Query listQuery = QueryBuilder
  .select(SelectResult.expression(Meta.id).as("metaId"))
  .from(DataSource.database(srcDb));

for (Result row: listQuery.execute()) {
  final String thisId = row.getString("metaId");

  final String json = srcDb.getDocument(thisId).toJSON(); ①
  Log.i(TAG, "JSON String = " + json);

  final MutableDocument hotelFromJSON = new MutableDocument(thisId, json); ②

  dstDb.save(hotelFromJSON);

  for (Map.Entry entry: dstDb.getDocument(thisId).toMap().entrySet()) {
    Log.i(TAG, entry.getKey() + " => " + entry.getValue());
  } ③
}
```


### クエリ結果

クエリの結果についても、`toJSON()`メソッドを使用して、JSON文字列に変換することができます。


```Java
// Uses Jackson JSON processor
import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();

ArrayList<Hotel> hotels = new ArrayList<Hotel>();

for (Result result : listQuery.execute()) {

  // Get result as JSON string
  String thisJsonString = result.toJSON(); ①

  // Get Java  Hashmap from JSON string
  HashMap<String, Object> dictFromJSONstring =
          mapper.readValue(thisJsonString, HashMap.class); ②


  // Use created hashmap
  String hotelId = dictFromJSONstring.get("id").toString();
  String hotelType = dictFromJSONstring.get("type").toString();
  String hotelname = dictFromJSONstring.get("name").toString();


  // Get custom object from JSON string
  Hotel thisHotel =
          mapper.readValue(thisJsonString, Hotel.class); ③

  hotels.add(thisHotel);

}
```

```KOTLIN
// Uses Jackson JSON processor
val mapper = ObjectMapper()
val hotels: ArrayList<Hotel> = ArrayList()

for (result in listQuery.execute()) {

    // Get result as JSON string
    val json = result.toJSON() ①

    // Get Hashmap from JSON string
    val dictFromJSONstring = mapper.readValue(json, HashMap::class.java) ②

    // Use created hashmap
    val hotelId = dictFromJSONstring["id"].toString() //
    val hotelType = dictFromJSONstring["type"].toString()
    val hotelname = dictFromJSONstring["name"].toString()


    // Get custom object from JSON string
    val thisHotel = mapper.readValue(json, Hotel::class.java) ③
    hotels.add(thisHotel)
}
```

- ① クエリ結果をJSON文字列として取得
- ② JSON文字列からネイティブオブジェクトを作成
- ③ JSONデータから作成されたディクショナリからカスタムオブジェクトを生成

#### JSON文字列形式

クエリで`ALL`を選択すると、JSON形式は次のようになります。

```JSON
{
  database-name: {
    key1: "value1",
    keyx: "valuex"
  }
}
```

クエリでプロパティのサブセットを選択した場合、JSON形式は次のようになります。

```JSON
{
  key1: "value1",
  keyx: "valuex"
}
```

### ディクショナリ
`toJSONtoDictionary`メソッドを使用してディクショナリーオブジェクトとJSONとの間で変換することができます。
JSON文字列として提供されたデータを使用して「MutableDictionaryObject」を初期化します。



```Java
final MutableDictionary mDict = new MutableDictionary(JSON); ①
Log.i(TAG, mDict.toString());

Log.i(TAG, "Details for: " + mDict.getString("name"));
for (String key: mDict.getKeys()) {
  Log.i(TAG, key + " => " + mDict.getValue(key));
}
```

```KOTLIN
val mDict = MutableDictionary(JSON) ①
Log.i(TAG, "$mDict")
Log.i(TAG, "Details for: ${mDict.getString("name")}")
for (key in mDict.keys) {
  Log.i(TAG, key + " => " + mDict.getValue(key))
}
```


### 配列
`toJSON()``toArray`メソッドを使用して、配列とJSONとの間で変換することができます。
JSON文字列として提供されたデータを使用して`MutableArrayObject`を初期化します。
また、`ArrayFragment`オブジェクトをJSON文字列に変換することができます。


例4.JSON文字列としての配列


```Java
final MutableArray mArray = new MutableArray(JSON); ①

for (int i = 0; i < mArray.count(); i++) { ②
  final Dictionary dict = mArray.getDictionary(i);
  Log.i(TAG, dict.getString("name"));
  db.save(new MutableDocument(dict.getString("id"), dict.toMap()));
}

final Array features = db.getDocument("1002").getArray("features"); ③
for (Object feature: features.toList()) { Log.i(TAG, feature.toString()); }
Log.i(TAG, features.toJSON()); ④
```

```KOTLIN
val mArray = MutableArray(JSON) ①
for (i in 0 until mArray.count()) {
    mArray.getDictionary(i)?.apply {
        Log.i(TAG, getString("name") ?: "unknown")
        db.save(MutableDocument(getString("id"), toMap()))
    } ②
}

db.getDocument("1002")?.getArray("features")?.apply {
    for (feature in toList()) {
        Log.i(TAG, "$feature")
    } ③
    Log.i(TAG, toJSON())
} ④
```

- ① JSON文字列で配列を初期化します
- ② 配列を使用して新しいドキュメントを作成して保存します
- ③ 新しいドキュメントからネイティブ配列オブジェクトを取得し、その要素を出力します
- ④ ドキュメントから配列をJSON文字列として取得します




### 関連情報


https://forums.couchbase.com/t/how-to-import-a-json-file-format-into-couchbase-lite-database-from-android/14362/4

https://github.com/couchbaselabs/UniversityLister-Android/blob/master/app/src/main/java/com/couchbase/universitylister/activities/ListActivity.java#L175

https://blog.couchbase.com/object-mapping-couchbase-mobile-android/