- Oracle Backend for Firebase(Fusabase)はローカル・キャッシュを実装していません。DocumentSnapshotおよびQuerySnapshotのメタデータのisFromCacheまたはfromCacheはつねにfalseを返します。
- スナップショット・リスナーが受け取る更新イベントを発生させる機構として、ロング・ポーリングとWebSocketの2種類があります。設定ファイルfusabase-config.jsonで、useSocket(またはuse_socket - SDKによって異なります)をtrueにするとWebSocketになります。falseのときはロング・ポーリングです。
- ロング・ポーリング(long polling)は名称の通り、クライアント側から定期的にサーバーに問い合わせを行い、変更を見つけた時にスナップショット・リスナーに更新イベントを送ります。
- ロング・ポーリングの場合、設定ファイルfusabase-config.jsonで、long_polling_intervalによりポーリング間隔を調整できます。単位は秒です。省略時は29秒、JavaScript SDKでは設定可能な値は5から300秒に制限されています。iOS SDKに制限はないようです。Android SDKでは10秒で固定されています。
- WebSocket場合はサーバー側の表にOracle Continuous Query Notification(CQN)が構成され、CQNで検知された更新がWebSocket経由でクライアントに送られます。useSocket(use_socket)がtrueの場合、ORDSとクライアント間でWebSocketによって接続されます。
- useSocketがtrueすなわち、Oracle CQNとWebSocketが通知に使用される場合、データ更新からクライアントへの通知までにかかる時間は1秒前後です。ロング・ポーリングの場合は、long_polling_intervalの設定に依存します。間隔を短くすると通知も速くなりますが、サーバー側への負荷は高くなります。
/**
* Subscribes to the {@code recipes} collection. When {@code category}
* is non-null, applies a {@code whereEqualTo("category", ...)} filter.
* Sorts by {@code createdAt} descending and limits to 24 results.
*
* <p>TODO Lab 4 — Task 1: Build the query and call
* {@code addSnapshotListener(...)}. Save the returned
* {@link ListenerRegistration} into {@link #recipesListener} so it can
* be removed later in {@link #stopListeningToRecipes()}.
*/
public void startListeningToRecipes(@Nullable String category) {
// TODO Lab 4
Query q = db.collection("recipes");
if (category != null) {
q = q.whereEqualTo("category", category);
}
q = q.orderBy("createdAt", Query.Direction.DESCENDING).limit(24);
recipesListener = q.addSnapshotListener((snapshot, error) -> {
if (error != null) {
errorMessage.postValue(error.getMessage());
return;
}
if (snapshot == null) return;
List<Recipe> mapped = new ArrayList<>();
for (QueryDocumentSnapshot doc : snapshot) {
Recipe r = doc.toObject(Recipe.class);
if (r != null) {
r.setId(doc.getId());
mapped.add(r);
}
}
recipes.postValue(mapped);
});
}
/**
* Subscribes to a single recipe document. Drives the recipe detail
* screen.
*
* <p>TODO Lab 4 — Task 3: Implement using
* {@code db.collection("recipes").document(recipeId).addSnapshotListener(...)}.
* Also start the ratings subcollection listener so the detail screen
* stays in sync when ratings are added in Lab 5.
*/
public void startListeningToRecipe(String recipeId) {
// TODO Lab 4
DocumentReference doc = db.collection("recipes").document(recipeId);
recipeDetailListener = doc.addSnapshotListener((snapshot, error) -> {
if (error != null) {
errorMessage.postValue(error.getMessage());
return;
}
if (snapshot == null || !snapshot.exists()) return;
Recipe r = snapshot.toObject(Recipe.class);
if (r != null) {
r.setId(snapshot.getId());
currentRecipe.postValue(r);
}
});
ratingsListener = doc.collection("ratings").addSnapshotListener((snapshot, error) -> {
if (error != null) {
errorMessage.postValue(error.getMessage());
return;
}
if (snapshot == null) return;
List<Rating> mapped = new ArrayList<>();
for (QueryDocumentSnapshot d : snapshot) {
Rating r = d.toObject(Rating.class);
if (r != null) {
r.setId(d.getId());
mapped.add(r);
}
}
currentRatings.postValue(mapped);
});
}
通常のコレクションでの確認
{
"schema": "testuser",
"app_name": "com.oracle.fusabase.recipeshare",
"app_type": "ANDROID",
"app_id": "59C27E98507C546FE063020012ACBFD3",
"objs_type": "dbfs",
"project_id": "59C1663EAB6F13DFE063020012AC5621",
"storage_bucket": "dbfs_BQYKZXSFPIUUWSH",
"auth_type": "base",
"auth_id": "59C1663EAB7313DFE063020012AC5621",
"ords_host": "http://10.0.2.2:8181/ords/testuser/",
"useSocket": false,
"enableLogging": true
}
タイトルがGarlic Butter Shrimpのレシピを使用して、fusabase-cliで以下の操作を行います。Androidアプリはデータの変更を見つけて、自動で画面を更新します。
- Garlic Butter Shrimpを検索しドキュメントIDとJSON本文を取得する。
- Garlic Butter Shrimpのレシピを削除する。AndroidアプリからGarlic Butter Shrimpが削除されることを確認する。
- Garlic Butter ShrimpのJSON本文を使って、fusabase-cliよりレシピを登録する。AndroidアプリにGarlic Butter Shrimpが表示されることを確認する。
- AndroidアプリでGarlic Butter Shrimpを選択する。
- Garlic Butter ShrimpのJSON本文を変更し、fusabase-cliよりレシピを更新する。AndroidアプリのGarlic Butter Shrimpの表示が更新されることを確認する。
{
"path": [ "recipes" ],
"conditions": [
{ "field": "title", "op": "=", "value": "Garlic Butter Shrimp" }
],
"limit": 1,
"explicitOrder": [
{ "field": "createAt", "direction": "asc" }
],
"aggregate": []
}
npx fusabase database query --path=query.json
fusabase % npx fusabase database query --path=query.json
⠋ Trying to fetch document..{ ret: [ { osons: [Object] } ] }
✔ List of OID within the collection:
Document ID VERSION DOCUMENT
59D961B5641AE3F8E063020012ACEA5D {"ingredients":["1 lb large shrimp","4 tbsp butter","4 cloves garlic","1/4 cup parsley","1 lemon"],"title":"Garlic Butter Shrimp","averageRating":0,"instructions":"Melt butter in a skillet over medium-high heat. Add minced garlic and cook for 30 seconds. Add shrimp and cook 2-3 minutes per side until pink. Finish with chopped parsley and a squeeze of lemon.","ratingCount":0,"description":"Quick weeknight dinner with shrimp tossed in garlic butter and parsley.","category":"Dinner","ownerId":"","createdAt":1787635746671,"prepTime":20,"createdBy":""}
fusabase %
npx fusabase database delete recipes/[Document ID]
fusabase % npx fusabase database delete recipes/59D961B5641AE3F8E063020012ACEA5D
Path is : recipes/59D961B5641AE3F8E063020012ACEA5D
✔ Collection delete Successfully:
{"message":"document deleted successfully!"}
fusabase %
{
"path": [
"recipes"
],
"data": {
"ingredients": [
"1 lb large shrimp",
"4 tbsp butter",
"4 cloves garlic",
"1/4 cup parsley",
"1 lemon"
],
"title": "Garlic Butter Shrimp",
"averageRating": 0,
"instructions": "Melt butter in a skillet over medium-high heat. Add minced garlic and cook for 30 seconds. Add shrimp and cook 2-3 minutes per side until pink. Finish with chopped parsley and a squeeze of lemon.",
"ratingCount": 0,
"description": "Quick weeknight dinner with shrimp tossed in garlic butter and parsley.",
"category": "Dinner",
"ownerId": "",
"createdAt": 1787635746671,
"prepTime": 20,
"createdBy": ""
}
}
npx fusabase database add --path=recipe.json
fusabase % npx fusabase database add --path=recipe.json
{"path":["recipes"],"data":{"ingredients":["1 lb large shrimp","4 tbsp butter","4 cloves garlic","1/4 cup parsley","1 lemon"],"title":"Garlic Butter Shrimp","averageRating":0,"instructions":"Melt butter in a skillet over medium-high heat. Add minced garlic and cook for 30 seconds. Add shrimp and cook 2-3 minutes per side until pink. Finish with chopped parsley and a squeeze of lemon.","ratingCount":0,"description":"Quick weeknight dinner with shrimp tossed in garlic butter and parsley.","category":"Dinner","ownerId":"","createdAt":1787635746671,"prepTime":20,"createdBy":""}}
✔ Document Added Successfully!!
{"OID":"59D961B5641BE3F8E063020012ACEA5D","VERSION":1}
fusabase %
{
"path": [
"recipes",
"59D961B5641BE3F8E063020012ACEA5D"
],
"data": {
"ingredients": [
"1 lb large shrimp",
"4 tbsp butter",
"4 cloves garlic",
"1/4 cup parsley",
"1 lemon"
],
"title": "Garlic Butter Shrimp - UPDATE",
"averageRating": 0,
"instructions": "Melt butter in a skillet over medium-high heat. Add minced garlic and cook for 30 seconds. Add shrimp and cook 2-3 minutes per side until pink. Finish with chopped parsley and a squeeze of lemon.",
"ratingCount": 0,
"description": "Quick weeknight dinner with shrimp tossed in garlic butter and parsley.",
"category": "Dinner",
"ownerId": "",
"createdAt": 1787635746671,
"prepTime": 20,
"createdBy": ""
}
}
npx fusabase database upd --path=recipe-upd.json
fusabase % npx fusabase database upd --path=recipe-upd.json
{"path":["recipes","59D961B5641BE3F8E063020012ACEA5D"],"data":{"ingredients":["1 lb large shrimp","4 tbsp butter","4 cloves garlic","1/4 cup parsley","1 lemon"],"title":"Garlic Butter Shrimp - UPDATE","averageRating":0,"instructions":"Melt butter in a skillet over medium-high heat. Add minced garlic and cook for 30 seconds. Add shrimp and cook 2-3 minutes per side until pink. Finish with chopped parsley and a squeeze of lemon.","ratingCount":0,"description":"Quick weeknight dinner with shrimp tossed in garlic butter and parsley.","category":"Dinner","ownerId":"","createdAt":1787635746671,"prepTime":20,"createdBy":""}}
✔ Document Updated Successfully!!
{"OID":"59D961B5641BE3F8E063020012ACEA5D","VERSION":3}
fusabase %
Relational to collection mappingによるコレクションでの確認
表RECIPESおよびRATINGSの作成およびRelational to collection mappingによるコレクションの作成とAndroidアプリケーションの変更手順については、記事「Oracle Backend for FirebaseのRelational to collection mappingを使ってJSON Duality Viewをコレクションとして使用する」にて紹介しています。
今回はデータがリレーショナル表であるRECIPESとRATINGSに保存されるため、データの変更にfusabase-cliの代わりに、これらの表を操作するAPEXアプリケーションを作成します。APEXとOracle Backend for Firebaseを共存させる環境については、記事「Oracle APEXが構成済みのデータベースにOracle Backend for Firebaseを構成する」で紹介しています。
grant all on recipes to apexdev;
grant all on ratings to apexdev;
SQL> grant all on recipes to apexdev;
Grantが正常に実行されました。
SQL> grant all on ratings to apexdev;
Grantが正常に実行されました。
SQL>
APEXのワークスペースにサインインし、空のアプリケーションを作成します。
























































