🦋
Serverpod ~JOIN機能なしで二段階検索
Future versions of Serverpod will add support for automatic joins and database views.
これを待ちならが他のコードを書いていたのだけれど、先に進めなくなってきたので、
二段階検索、実装してみる。
外部キーを使えば簡単、みたいな話なのだが、外部キーって「親子関係」がある。
親削除したら、子どももみんな削除だぜ、みたいな。(無効にもできるらしいけど)
なので今回は、単純にフラットな関係の二つのtableを、中間tableで繋ぎます。
まずtableAとtableABに同時にデータを入れる。
例えば「2003年5月9日、小惑星探査機はやぶさ打ち上げ」がtableAに入る。
「JAXA」「内之浦宇宙空間観測所」はtableBに入っている。
これらは当然、別のデータとも繋がっているので、多対多の関係になる。
tableBのIDが引数になっている。
Future<int> save(Confirm confirm) async {
if (***) {
try {
var principal = Principal(
******
);
var principalId = await client.principal.addPrincipal(principal);
//ここまでがtableAへの入力。最後の行で取ったIdを使う。
//繋ぐべきtableBのデータのIdのList<int>は既に取ってある。
//これはFlutter側の話なので、今回は割愛
//tableABへの入力
if (confirm.selectedOrgId.isNotEmpty) {
for (var orgId in confirm.selectedOrgId) {
var pOrgs = PrincipalOrgs(
principal_id: principalId, org_id: orgId);
var principalOrgsId = await client.principalOrgs.addPOrgs(pOrgs);
debugPrint('Added Orgs involved : $principalOrgsId');
}
}
}
次はJAXAをkeywordに、いろいろな宇宙探査について検索する。
endpointに関数を設定する。
これはtableAに対応するendpointに書いた。
もちろんListなので複数の用語でor検索が可能。
and検索は未対応。
//tableBのIdでtableAを検索する関数
Future<List<Principal>> getPrincipalByOrgsId(Session session, {List<int>? orgIds}) async {
if (orgIds == null || orgIds.isEmpty) {
return Future.value([]); // Return empty list if no orgIds are provided
}
// Step 1: Get principalIds from PrincipalOrganisation using orgIds
var whereClausePrincipalOrganisations;
for (var orgId in orgIds) {
if (whereClausePrincipalOrganisations == null) {
whereClausePrincipalOrganisations = PrincipalOrgs.t.org_id.equals(orgId);
} else {
whereClausePrincipalOrganisations = whereClausePrincipalOrganisations | PrincipalOrgs.t.org_id.equals(orgId);
}
}
var PrincipalOrgsResults = await PrincipalOrgs.find(session, where: (_) => whereClausePrincipalOrganisations);
var principalIds = PrincipalOrgsResults.map((row) => row.principal_id).toList();
// Step 2: Get Principals using principalIds
var whereClausePrincipal;
for (var principalId in principalIds) {
if (whereClausePrincipal == null) {
whereClausePrincipal = Principal.t.id.equals(principalId); // Assuming the id field in Principal table is named 'id'
} else {
whereClausePrincipal = whereClausePrincipal | Principal.t.id.equals(principalId);
}
}
return await Principal.find(
session,
where: (_) => whereClausePrincipal,
orderBy: Principal.t.point,
);
}
で、Flutterから呼ぶのはこれだけ。
JAXAのIdは既に取れているという前提。これも今回は割愛。
fetchPrincipalByOrgsId({List<int>? listOrgIds}) async {
try {
_principal = await client.principal.getPrincipalByOrgsId(orgIds: listOrgIds);
print("Getting principal with OrgIds: $listOrgIds");
notifyListeners();
} on Exception catch (e) {
debugPrint('$e');
}
}
これで、JAXA関連のいろんなデータが年代順に並ぶ。
これが最適解かどうかわからないけど、ちゃんと動くので。
いずれJOIN機能に差し替えるまでこれでいこうと思う。
Discussion