2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Couchbase Server N1QLクエリ解説(RDBとの差分の観点から)

Posted at

基本

 エスケープ文字

ユーザー定義語句(バケット名、フィールド名)は、「`」を使ってエスケープすることによって、予約語との衝突を回避することができます。
Couchbase Serverでは、「-」は、予約語に含まれるため、「-」を含むバケット名を利用する場合、下記のようにバケット名をエスケープする必要があります。

SELECT ... FROM `travel-sample`

構造

N1QLは、JSONデータを構成する文字列、数値、真偽値を(直接的に、つまり文字列としてエスケープされた形ではなく)含むことができます。以下に具体的な例を見てみます。

コンストラクションオペレーター

以下の記号は、コンストラクションオペレーターと呼ばれます。
{, }, :, [, ]

ネステッドオペレーター・エクスプレッション

以下の表現は、ネステッドオペレーター・エクスプレッションと呼ばれrます。

  • ドットノーテーション (.
  • 配列表現(インデックス、スライス)

ドキュメントキー

USE KEYS
SELECT *
FROM `travel-sample`
USE KEYS "airport_1254";
SELECT *
FROM `travel-sample`
USE KEYS ["airport_1254","airport_1255"];

USE KEYS のみを利用してクエリを行う場合、インデックスを作成する必要がありません。

注意: Couchbase Serverでは、ドキュメントキーが判明している場合には、ドキュメントキーを指定してドキュメントを取り出すことが、(RDBにおける、主キーでの検索のように)最も効果的であることは間違いありません。一方でドキュメントキーが判明しているケースにおいては、性能を追求する場合、必ずしもクエリ用いて(Queryサービスを介して)ドキュメントを取り出す必要はなく、Dataサービスに対して直接リクエストすることで性能を最適化することが可能です(特に上記の例のような単純な利用の場合。一方、サブクエリを伴うような複雑なクエリの場合など、USE KEYS句を効果的に利用できる場面があります)。

META().id

上記のUSE KEYS を利用したクエリは、下記のようにMETA().id を使って書き直すことができます。

SELECT *
FROM `travel-sample`
WHERE META().id IN ["airport_1254","airport_1255"];

META().id を利用してクエリを行う場合、META().idを用いたインデックスが作成されている必要があります。

USE KEYSの構文では、後続する鉤括弧の中のドキュメントキーは完全一致が想定されていますが、META().id を利用する場合、N1QLクエリの一部として、LIKE と組み合わせることができ部分一致検索を行うことができる他、比較演算子による大小比較など、クエリの名で用いる際により自由度が高い表現と言えます。

また、検索条件としてのみではなく、SELECT META().id FROM ... WHERE ...のように、条件に一致するドキュメントキーを検索するために用いることもできます。

上記のクエリ中のMETA().id の部分は、下記のように、バケット名を含んだ表現を用いることができます。このクエリのように、クエリの中でキースペース(バケット名)が一意に決まっている場合、指定は必須ではありません。複数のキースペースが混在している中で、ドキュメントのキーを用いる(取り出す)場合には、キースペースを指定した表現を用います。

SELECT *
FROM `travel-sample`
WHERE META(`travel-sample`).id IN ["airport_1254","airport_1255"];

N1QLキーワード

フィールドの操作

RAW | ELEMENT | VALUE

これらは全て同義語です(以下では、RAW を用います)。

N1QLで検索された結果は、JSONデータとして、フィールド名と値のペアとなることが基本ですが、RAWキーワードをSELECT句と共に用いることで、JSONデータの値のみを取り出すことができます。

RAWを用いない例

クエリ

SELECT city
FROM `travel-sample`
WHERE type = "airport"
ORDER BY city
LIMIT 5;

結果

[
  {  "city": "Abbeville"  },
  {  "city": "Aberdeen"  },
  {  "city": "Aberdeen"  },
  {  "city": "Aberdeen"  },
  {  "city": "Abilene"  }
]
RAW を用いた例

クエリ

SELECT RAW city
FROM `travel-sample`
WHERE type = "airport"
ORDER BY city
LIMIT 5;

結果

[
  "Abbeville",
  "Aberdeen",
  "Aberdeen",
  "Aberdeen",
  "Abilene„
]

DISTINCT と組み合わせた利用例

SELECT DISTINCT RAW city
FROM `travel-sample`
WHERE type="airport"
ORDER BY city LIMIT 5;
[
  "Abbeville",
  "Aberdeen",
  "Abilene",
  "Adak Island",
  "Addison"
]

配列

コレクション形データを操作するための、コレクションオペレーターとして以下があります。

ANY, EVERY, ARRAY, FIRST, EXISTS, IN, WITHIN

選択項目としての配列利用

ARRAY またはFIRSTから始まり、ENDで基本単位となります。
IN またはWITHINFORにより、コレクションの要素へのループを表現しています。

( ARRAY | FIRST ) var1 FOR var1 ( IN | WITHIN ) expr1 END

WHEN 句により、条件指定を付け加えることが可能です。

( ARRAY | FIRST ) var1 FOR var1 ( IN | WITHIN ) expr1 [ ( WHEN cond1 [ AND cond2 ] ) ] END

下記の通り、,により、上記説明した内容を複数並べて用いることができます。

( ARRAY | FIRST ) var1 FOR var1 ( IN | WITHIN ) expr1 
   [ ,  var2 ( IN | WITHIN ) expr2 ]*
   [ ( WHEN cond1 [ AND cond2 ] ) ] END

検索条件としての配列利用

ANY またはEVERYから始まり、ENDまでで基本単位となります。SATISFIESで条件を指定します。

( ANY | EVERY ) var1 ( IN | WITHIN ) expr1
   [ , var2 ( IN | WITHIN ) expr2 ]*
   SATISFIES condition  END

注意:  この構文は、配列から、真となった要素を取り出しているのではないことに注意してください。これは、SQLのWHERE条件が検索に使ったカラムを取り出すものではないのと同様です。

ANY

配列に条件で指定した要素が一つでも含まれる場合、真となります。

SELECT *
FROM purchases
WHERE ANY item IN purchases.lineItems SATISFIES
item.count >= 5 END
EVERY

配列の全ての要素が、指定した条件に一致する場合、真となります。

SELECT *
FROM purchases
WHERE EVERY item IN purchases.lineItems SATISFIES
item.count >= 5 END
INまたはWITHIN

IN 句が、指定された配列のトップレベルの要素を検索するのに対して、WITHIN句は、現在の配列とその子、および子孫を含めて検索対象とします。

ドキュメントキーによる結合 : NEST

NESTは、外部の子ドキュメントを親の下に埋め込む特別なタイプのJOINです。
ドキュメント・キーを介した参照関係でデータをモデル化した際に用いる事ができます。ON KEYSにより、対象とするドキュメントのキーを指定することができます。

ドキュメントキー:o1
{"order_id":1234,
      "type":"Order",
      "customer_id":"34567",
      "total_price":"65.5",
      "lineitems":["o11","o12","o13"]
}
ドキュメントキー:ol1
{"lineitem_id":o11,
      "type":"lineitem",
      "item_id":"789",
      "qty":"3",
      "itemprice":"5.99",
      "base_price":"17.97",
      "tax":"0.75",
      "total_price":"18.22"
}
ドキュメントキー:ol2
{"lineitem_id":o12,
      "type":"lineitem",
      "item_id":"234",
      "qty":"5",
      "itemprice":"10.00",
      "base_price":"50.00",
      "tax":"0.75",
      "total_price":"50.75"
}

SELECT ordr.order_id, 
ARRAY {item_id: l.item_id, quantity:l.qty} FOR l IN line END as items
FROM `retailsample` ordr
NEST `retailsample` line
ON KEYS ordr.lineitems 

結果は、下記のように、一つのドキュメントになります。

[
  {
    "items":[
      {"item_id":"789", "qty":"3"},
      {"item_id":"234", "qty":"5"}
      ];
    "order_id":"1234"
  },
  {
    "items":[
      {"item_id":"899", "qty":"8"},
      {"item_id":"651", "qty":"2"}
      ];
    "order_id":"9812"
  },
]

サブドキュメントのフラット化: UNNEST

UNNESTは、ネストされたオブジェクトを最上位ドキュメントとして表示するために用います。

下記のようなネストされた構造を持つデータを想定します(受注明細データを中に含む受注伝票データ)。

{
  "ordId": "ORDER-0001",
  "status": "Shipped",
  "items": [
     {
     "prodId": "AAA-222",
     "qty": 1
     },
    {
     "prodId": "BBB-333",
     "qty": 2  
    },
    {
     "prodId": "CCC-444",
     "qty": 3 
    }
  ]
}

UNNESTは、このようなネストされた(サブドキュメントを含む)ドキュメントへのクエリの結果を下記のようなテーブル構造として利用したい時に使われます。

ordId Status prodId qty
ORDER-0001 Shipped AAA-222 1
ORDER-0001 Shipped BBB-333 2
ORDER-0001 Shipped CCC-444 3

クエリでは、UNNEST をサブドキュメントに対して指定し、as で別名をつけたものをSELECT 句の中で使用します。

SELECT ord.ordId, ord.status, item.* FROM orders ord UNNEST items as item

下記のようなフラットな構造のJSONが取り出されます。

[
{ “ordId”: “ORDER-0001, “status”: “Shipped”, “prodId”: “AAA-222, “qty”: 1 },
{ “ordId”: “ORDER-0001, “status”: “Shipped”, “prodId”: “BBB-333, “qty”: 2 },
{ “ordId”: “ORDER-0001, “status”: “Shipped”, “iprodId”: “CCC-444, “qty”: 3 }
]

(JSON中の要素の出現順はこの通りではありません)

情報: JSONオブジェクトのフィールドは並び順に意味を持ちません。

SQLと比べた場合の制約

  • FULL [OUTER] JOIN はサポートされていません
  • CROSS JOIN はサポートされていません
  • RIGHT [OUTER] JOIN は、JOIN連結の最初の (または唯一の) クエリである必要があります

参考情報:コミュニティエディションとエンタープライズエディションの違い

クエリに関連した、コミュニティエディションには含まれない、エンタープライズエディションの機能として、以下があります。

機能
  • ウィンドウ関数
  • FLEXインデックス(クエリからの全文検索インデックス利用)
性能・最適化
  • コストベースオプティマイザ(CBO)
  • 無制限のクエリ同時実行
  • N1QLアグリゲートプッシュダウン
マネジメント
  • N1QLリクエストの監査
  • クエリのモニタリング

参考資料

チートシート

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?