0
0

More than 1 year has passed since last update.

Couchbase Lite機能 解説:配列データへのクエリ

Last updated at Posted at 2022-03-11

はじめに

ここでは、Couchbase Liteデータベースで配列を含むJSONドキュメントへクエリする方法について解説します。

なお、Couchbase Mobileについては、Couchbase Mobileアプリケーション開発へのロードマップに記事をまとめている他、(これらの記事を元に構成した)以下の電子書籍を無償で頒布しています。

また、Couchbase Mobileは、Couchbase LiteとCouchbase Serverとのデータ同期機能を提供します。Couchbase Serverの存在意義、機能詳細、利用方法等については、拙著NoSQLドキュメント指向データベースCouchbase Serverファーストステップガイド(インプレスR&D刊)や、NoSQL/JSONデータベースCouchbase Server理解・活用へのロードマップにまとめてある記事をご参考ください。

配列データへのクエリ

配列は、JSONデータモデリングの不可欠な要素です。ここでは、配列データへのクエリについて説明します。

ここで説明する例ではiOS用のSwiftを使用していますが、シンタックス上の違いはあれど、同じクエリインターフェイスがAndroid等他のプラットフォームでも利用可能です。

サンプルプロジェクト

サンプルのSwiftプロジェクトに興味がある場合は、以下の手順に従ってください

GitHubからiOS Swift Playgroundのクローンを作成します

$ git clone https://github.com/couchbaselabs/couchbase-lite-ios-api-playground

対応するREADMEファイルのインストール手順に従って、構築して実行します。

データモデル

ここでは、ホテルに関する情報を表す以下のJSONドキュメントモデルを用いて説明します。
(簡潔化のために、サンプルデータのモデルからいくつかのプロパティを省略しています)。

このデータモデルには、文字列の配列(public_likes)や、ネストされたオブジェクトを要素として持つ配列(reviews)が含まれています。

 {
   "type": "hotel",
   "name": "Medway Youth Hostel",
   "address": "Capstone Road, ME7 3JE",
   "city": "Medway",
   "country": "United Kingdom",
   "description": "blah blah",
   "public_likes": [
     "Julius Tromp I",
     "Corrine Hilll"
   ],
   "reviews": [
   {
     "author": "Ozella Sipes",
     "content": "blah blah.",
     "date": "2013–06–22 18:33:50 +0300",
     "ratings": {
       "Cleanliness": 5,
       "Location": 4,
       "Overall": 4,
       "Rooms": 3,
       "Service": 5,
       "Value": 4
     }
   },
 {
   "author": "Jeremy Snapes",
   "content": "blah blah.",
   "date": "2013–05–05 18:33:50 +0300",
   "ratings": {
       "Cleanliness": 2,
       "Location": 2,
       "Overall": 4,
       "Rooms": 3,
       "Service": 5,
       "Value": 4
     }
   }
 ],
  "url":"http://www.yha.org.uk",
  "vacancy": true
}

配列の要素による検索

以下の例では、public_like配列プロパティに「Corrine Hillll」の値が含まれているドキュメントを検索しています。

let searchQuery = QueryBuilde.select(SelectResult.expression(Meta.id),
                  SelectResult.expression(Expression.property("name")),
                  SelectResult.expression(Expression.property("public_likes")))
 .from(DataSource.database(db))
 .where(Expression.property("type").equalTo(Expression.string("hotel"))
 .and(ArrayFunction.contains(Expression.property("public_likes"), value: Expression.string("Corrine Hilll"))))

ArrayFunction.containsのように、ArrayFunctionクラスのcontains(スタティック)メソッドを利用します。

配列サイズ取得

以下の例では、 配列のサイズを取得します。

 let searchQuery = QueryBuilder.select(SelectResult.expression(Meta.id),
           SelectResult.expression(Expression.property("name")),
           SelectResult.expression(ArrayFunction.length(Expression.property("public_likes"))).as("NumLikes"))
 .from(DataSource.database(db))
 .where(Expression.property("type").equalTo(Expression.string("hotel")))
 .limit(Expression.int(limit))

ArrayFunction.length(Expression.property("public_likes"))のように、ArrayFunctionクラスのlength(スタティック)メソッドを利用します。

また、as("NumLikes"))のように、サイズを取得した結果に「NumLikes」という名前をつけます。
式の結果をエイリアスしない場合、プロパティキーは自動的に生成されるため、明示的に名前をつけることによって、プログラムの可読性を増すことができます。

配列メンバーの評価

ArrayFunction.containsメソッドを使用して、指定された配列に特定の値が含まれているかどうかを確認できることを紹介しましたが、Couchbase Liteには、より、強力なフィルタリング機能が用意されています。

以下の例は、public_like配列プロパティに「Cor」から始まる値が含まれているドキュメントを検索しています。

 let VAR_LIKEDBY = ArrayExpression.variable("likedby")
 
 let searchQuery = QueryBuilder.select(SelectResult.expression(Meta.id),
                  SelectResult.expression((Expression.property("public_likes"))))
.from(DataSource.database(db))
.where(Expression.property("type").equalTo(Expression.string("hotel"))
.and(ArrayExpression.any(VAR_LIKEDBY).in(Expression.property("public_likes"))
.satisfies(VAR_LIKEDBY.like(Expression.string("Cor%")))))
.limit(Expression.int(limit))<code>

まず、public_likes配列内のすべての要素(要素のイテレーション)を表すために、VAR_LIKEDBYという変数を宣言しています(ここで用いる名称は任意のものです。いわばFORループの内部で用いられる変数と考えると理解しやすいでしょう)。

この変数と評価対象の配列との組み合わせで、ArrayExpression.any(VAR_LIKEDBY).in(Expression.property("public_likes"))のように、an <変数> in <配列>という構文を用いて、クエリを構築します。

それに続く、.satisfies(VAR_LIKEDBY.like(Expression.string("Cor%")))では、満たすべき条件〜項目の値が「Cor」で始まるかどうか〜チェックしています。

インデックスによる配列アクセス

以下のように、インデックス指定により要素をクエリすることができます。

 let searchQuery = QueryBuilder.select(SelectResult.expression(Meta.id),
           SelectResult.expression(Expression.property("name")),
           SelectResult.expression(Expression.property("public_likes[0]")))
 .from(DataSource.database(db))
 .where(Expression.property("type").equalTo(Expression.string("hotel")))
 .limit(Expression.int(limit))

ここで、Expression.property("public_likes[0]")は、public_likes配列のはじめの要素を指します。

ネストされた配列の評価

ネストされた配列のメンバーを評価できます。

上記のデータモデルからわかるように、reviewsプロパティはオブジェクトの配列を保持します。各オブジェクトにはratingsという(ディクショナリ)プロパティが含まれています。

次のクエリ、複数種類存在するレーティングの内、Overallでの評価が4以上のドキュメントを返します。


 let VAR_OVERALL = ArrayExpression.variable("review.ratings.Overall")

 let VAR_REVIEWS = ArrayExpression.variable("review")

 let searchQuery = QueryBuilder.select(SelectResult.expression(Meta.id),
          SelectResult.expression(Expression.property("name")))
 .from(DataSource.database(db))
 .where(Expression.property("type").equalTo(Expression.string("hotel"))
 .and(ArrayExpression.any(VAR_REVIEWS).in(Expression.property("reviews"))
 .satisfies(VAR_OVERALL.greaterThanOrEqualTo(Expression.int(4)))))
 .limit(Expression.int(limit))

まず、review.ratings.Overall要素を表す変数を宣言しています。

そして、reviews配列内のすべての要素を表す変数を宣言しています

ArrayExpression.any(VAR_REVIEWS).in(Expression.property("reviews")) .satisfies(VAR_OVERALL.greaterThanOrEqualTo(Expression.int(4))が条件指定箇所ですが、any ~ in ~ satisfiesという全体の構造は、上述の単純なケースと同じであることが同じです。

satisfiesメソッドの引数として、ネストされたオブジェクトのプロパティをドット表記で指定した変数を定義することによって.greaterThanOrEqualTo(Expression.int(4))のように、そのプロパティの値を条件として、フィルタリングを行うことができます。

関連情報

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0