データモデルのクエリ [ver.1.2.0]
hifiveでは、データモデルに対してクエリを発行し、条件にマッチするオブジェクトだけを取り出したり特定の順序に並べたりすることができる(ver.1.2より)。
以下に、クエリの書き方の詳細を説明する。
クエリ機構の概要
クエリ機構は、大きく「フィルタリング」(特定の条件にマッチするオブジェクトだけを取り出す)と「ソート」の2つの機能からなる。
なお、クエリは非同期的に実行される(場合がある)ので注意すること。
基本的な使い方
クエリは、データモデルが持つcreateQuery()メソッドで作成する。戻り値はQueryオブジェクトである。
フィルタリング条件を設定したい場合は、QueryオブジェクトのsetCriteria()メソッド
ソート順を設定したい場合は、QueryオブジェクトのaddOrder()メソッドを使用する。
最後に、execute()メソッドを呼び出してクエリを実行する。execute()の戻り値はQueryResultオブジェクトである。
QueryResultオブジェクトはresultプロパティを持ち、この中にクエリ結果が配列で入っている
(配列の各要素はデータアイテムオブジェクト)。
例:
query.setCriteria({ 'age >': 25 }); //ageが25より大きいデータのみを含める
query.addOrder('age'); //ageの昇順でソート
var queryResult = query.execute();
//queryResult.resultにクエリ結果が格納されている。
また、クエリの各メソッドはクエリインスタンス自身を戻り値として返すので、
以下のようにメソッドチェーンで記述することもできる。
var queryResult = query.execute();
//queryResult.resultにクエリ結果が格納されている
フィルタリング(条件の記述)
基本的な使い方
条件は、条件オブジェクトとして記述する。オブジェクトの各プロパティは条件句として扱われる。
条件オブジェクトのプロパティのキー(名前)には「対象となるオブジェクトのプロパティ名」を書き、その値には満たすべき条件を記述する。
複数の条件句を記述した場合、デフォルトではAND条件として扱われる。
例:
var data = [
{ id: 1, name: 'tanaka', age: 25 },
{ id: 2, name: 'tanaka', age: 30 },
{ id: 3, name: 'kato', age: 40 }
];
//条件オブジェクト(この場合、上記データに対してクエリを実行するとid:1とid:2のオブジェクトがヒットする)
var criteria = {
name: 'tanaka', //プロパティ名はクエリ対象オブジェクトのプロパティ、値は満たすべき条件
age: 25 //複数の条件句を書いた場合、デフォルトではAND条件として扱われる
};
値の比較(以上、以下などの範囲指定、比較演算子の指定)
条件オブジェクトのプロパティ名には演算子を記述することができる。
演算子は、対象プロパティの後ろにスペースで区切って記述する。
既定では以下の演算子が指定可能。省略した場合は「=」を指定したとみなす。
なお、下記演算子では、Date型での比較も可能である。Date型の比較は、内部的にはgetTime()により行われる。
Date型で比較したい場合、条件値とチェック対象のデータの両方がDate型でなければならない。
演算子 | 意味 |
---|---|
= | 等しい |
!= | 等しくない |
> | より大きい |
>= | 以上 |
< | より小さい |
<= | 以下 |
in | 指定された配列内のいずれか値と一致する。値は配列で指定する。 |
!in | 指定された配列内のいずれの値とも一致しない。すなわち、inの否定。値の指定方法はinと同じ。 |
between | 指定された値の範囲内かどうか(境界値を含む)。範囲は配列で指定し、1つめの要素に下限値、2つめに上限値を指定する。(例:'age between': [20, 30]) |
!between | 指定された範囲の外かどうか(境界値を含まない)、すなわち、betweenの否定。値の指定方法はbetweenと同じ。 |
例:
var criteria = {
'age >=': 30
};
条件句の値が正規表現の場合
条件句では、値に正規表現を取ることができる。
この場合、「=」による比較とみなす。つまり、データが正規表現にマッチする場合に条件を満たしたと判断する。
比較演算子に=以外を指定した場合は例外が発生する。(従って、通常「=」は指定しなくてよい。)
例:
var criteria = {
name: /(tanaka|suzuki)/
};
ユーザー定義関数の使用
条件句として関数を設定すると、その関数を実行して条件にマッチするか否かを判定する。
この場合、プロパティ名の意味(比較演算子等)は無視される。
なお、他に条件句を書いた場合、ユーザー定義関数は条件句の一つとして扱われる。
(AND条件の場合、ユーザー定義関数がtrueを返し、かつ他のすべての条件を満たした場合のみマッチする。)
関数は、以下の形式で定義する。
//条件にマッチする場合はtrue、しない場合はfalseを返す。
//何も返さなかった場合、またはtrue/false以外の値を返した場合はfalseとみなす。
}
例:
if(data.get('name') === 'tanaka') {
return true;
}
return false;
}
//データオブジェクトごとにisValidNameが呼ばれる。
//nameがtanaka、かつageが20以上のデータがマッチする。
var criteria = {
nameChecker: isValidName,
'age >=': 20
};
ANDとOR(論理演算子の変更)
条件オブジェクトに__opプロパティを記述すると、各条件句の論理演算子(デフォルトはAND)を変えることができる。
既定では「or」と「and」が指定可能。省略した場合は「and」を指定したものとみなす。
※「__op」という名前のプロパティを対象にして条件句を書きたい場合は{ '__op =': 13 }のように比較演算子を付けて記述する。
例:
var criteria = {
__op: 'or',
name: 'tanaka',
'age <': 30
}
条件の複合(AND条件・OR条件の組み合わせ)
条件オブジェクトはネストすることができる(条件句として条件オブジェクトを持たせることができる)。
条件句の値がオブジェクトの場合、その条件句はネストした条件オブジェクトとみなす。
この場合、プロパティの名前は無視される(演算子などを書いても意味がない)。
var criteria = {
__op: 'or',
name: 'tanaka',
ageRange: { //キー名は何でもよい(ネストした条件オブジェクトの意味を表す名前にすることを推奨)
'age >=': 25,
'age <': 30
}
};
ソート
QueryオブジェクトのaddOrder()で、ソート順を制御できる。
(addOrder()でソート順を指定しなかった場合、クエリの戻り値に含まれるオブジェクトの順序は不定。)
キー名指定によるソート
addOrderは、引数として、ソートするキー名と昇順・降順を指定する。(昇順・降順は省略可能。省略時は昇順となる。)
複数のキーで順序を指定したい場合は、addOrder()を複数回よぶと呼び出した順(addした順)に第一ソートキー、第二ソートキー、…を指定できる。
(指定されたすべてのキーで同値と判定される要素があった場合、それらの要素の並び順は不定である。)
昇順・降順の指定
addOrderの第2引数にtrueを指定した場合、または第2引数を省略した場合、そのキーについて昇順でソートする。
第2引数にfalseを指定すると降順でソートする。
例
query.addOrder('age' true); //ageの昇順でソート
query.addOrder('age' , false); //ageの降順でソート
query.addOrder('age', false).addOrder('recentVisit'); //ageの降順でソート、ただしageが同じ要素についてはrecentVisitの昇順でソート
ユーザー定義ソート関数によるソート
関数を指定する場合、下記のようなユーザー定義ソート関数である必要がある。実行時はこれを自動的に呼び出し、
その戻り値に基づいてソートを行う。
なお、setOrderFunctionとaddOrderは同時には使用できない。
ユーザー定義ソート関数仕様:
function compareFunction(item1, item2) {
//戻り値は以下の通りに返すこと:
//item1をitem2より前に並べる場合は0より小さい値(負の数値)
//item1とitem2の順序が同じ場合は0
//item1をitem2より後に並べる場合は0より大きい値(正の数値)
}
例
//aのageがbのageより小さい(a < b)場合に正、a > bの場合に負なので、
//結果としてageの昇順でソートされる
return a.get('age') - b.get('age');
});