What are we doing for things we want?

What are we doing for things we want?

Mac Mini ဝယ်ရမလား iPad Pro ဝယ်ရမလား?

အလုပ်အတွက်ကတော့ Mac Mini က ပိုကောင်းတယ်။ ပိုပြီးအသုံးဝင်မယ်။ iPad Pro ကတော့ ကိုယ့်ရဲ့ အာသီသအတွက်။ အလုပ်အတွက်လည်း အနည်းနဲ့အများ အထောက်အကူပြုမယ်ဆိုပေမယ့် Mac Mini နဲ့ တော့ မယှဉ်သာဘူး။

နှစ်ခုလုံး ဝယ်နိုင်အောင် လုပ်တာပေါ့။

MAP-BY-KMT က Ads ကိစ္စ ပြီးရင် အကုန်ပြီးပြီ ပြောရမယ်။

iPad Pro အတွက်က Movie Streaming ကို အာရုံစိုက်ရမှာပေါ့ ။ ဒီ Janaray တစ်လ အာရုံစိုက်ပြီးလုပ်ရင် ရမယ်ထင်တယ်။

iPad Pro က instance pleasure ကို ရမယ်။ second screen ရမယ်။ pan နဲ့ ဘာနဲ့ စာသင်တဲ့အခါ အဆင်ပြေကောင်း ပိုပြေလာမယ်။

mac mini ကတော့ ပြန်ရောက်တဲ့အခါ ပိုပြီး Professional ဆန်လာမယ်။

နှစ်ခုလုံးကတော့ မြန်မာနိုင်ငံမှာဆို ဝယ်ဖို့ အဆင်မပြေတဲ့ ပစ္စည်းတွေ။ စျေးနဲ့ availability

နောက်တစ်ခုက ဒီမှာ Encraving ရတယ်။ ဒါကလည်း iPad Pro ဝယ်ဖို့အတွက် တွန်းအားတစ်ခုပဲ။

စိတ်ထဲမှာတော့ iPad Pro က အားသာနေတယ်။ ဒါသုံးပြီး လုပ်ငန်းအရ အထောက်အကူပြုမှာလားဆိုတာကတော့ သိပ်ပြီး ထိရောက်မှာ မဟုတ်ဘူး။

iPad Pro အရင်ဝယ်ပြီး နောက်လမှ Mac Mini ဝယ်ရင်ကောင်းမလား? ဒါကတော့ ဘုရင့်နောင် ဖောင်ဖျတ်တဲ့ ကိန်းပဲ။

256 SSD တစ်ခုလည်း ဝယ်ရမယ်။ SanDisk က ထုတ်တာလေး စျေးလည်းမဆိုးဘူး။ Design ကလည်း Type C နဲ့ Type A နှစ်ခုလုံးပါတော့ မိုဘိုင်းရော ကွန်ပျူတာရော အဆင်ပြေမယ့် သဘော။

Mac Mini က M2 စောင့်လိုက်ပြီး M2 ပါတဲ့ iPad Pro အရင်ဝယ်လိုက်မယ်။ :D

KM ❤️ MSD 2022-02-04

// TODO: make video about ordering ipad pro in india with Graving

အိုကေ 80,000 တန် iPad Pro တစ်လုံး ဝယ်မယ်။

mahar-by-ksmt ဒါကတော့ အိမ်အတွက် ရည်ရွယ်ထားလိုက်မယ်။ သိန်း (၃၀) တစ်လ ၊ နာရီပေါင်း ၂၄၀ =

လုပ်နိုင်တယ်လို့ အရင်ယုံထားရမယ်။ လိုချင်တာတွေကတော့ အများကြီးပေါ့။ စိတ်တွေတောင် နောက်ကျိသွားဉီးမယ်။ တစ်ခုချင်းစီကို အာရုံစိုက်ပြီးလုပ်ပါ။ ရှောင်သင့်တာတွေရှောင်။ စိတ်ကလေးကို တစ်ခုတည်းမှာ စူးစိုက်ပြီး အလုပ်လုပ်။

ကျွဲကူးရေပါ ဖြစ်အောင်က Chat ကို MAP မှာ ထည့်ပေးရမယ်။

comment စနစ် အရင်ထည့်ရမယ်။

wordpress မှာ မတွဲဘဲ ဒီ app တစ်ခုလုံးအတွက် သီးသန့် စနစ်တစ်ခု လုပ်ထားရမယ်။

database က နှစ်ခု ဖြစ်နေမယ်။ wordpress က အဖွဲ့တွေက Server to Server API နဲ့ ပြောရမယ့် သဘောမှာ ရှိမယ်။ data ယူတာ ထည့်တာ နဲ့ ပတ်သက်ပြီ။ data ထည့်တာကတော့ client ဘက်က တိုက်ရိုက်လုပ်လို့ရမယ်။ data ထုတ်တဲ့နေရာမှာ wordpress ကနေ ဒီဘက်က chat-solution ကို api ကနေပဲ လှမ်းမေးရမယ်။

User Account

ကိုယ်ပိုင် email , password နဲ့ ပဲ အရင် register လုပ်ခိုင်းမယ်။ နောက်ပိုင်းမှာ firebase auth နဲ့ verification လုပ်တာမျိုးတွေ လုပ်မယ်။

Public Chatroom

စာ၊ ပုံ , Video , Audio , File အကုန်ပို့နိုင်မယ်။ လောလောဆယ် ဖိုင် size ကို limit လုပ်ထားမယ်။

one to one chat

message

from user_id to user_id | group_id type one_to_one | group

What are we doing?

books in map-by-kmt

that’s also great.

flutter-dev

from zero to hero

This Evening

  • OOAK -> filter and pagination with query builder for multiple filter

POS

Chat Solution

  • ui layout
  • Basic Entity

mahar-by-ksmt

  • firebase realtime - database

100 - 5 USD / month

5 * 3000 => 15,000 per month

User တစ်ရာကို 15,000

User တစ်ယောက်ကို 150 လောက် ကျမယ်။ ဒါက server ဖိုး။

Cloud Function နဲ့ Realtime Database ဒါပဲ သုံးမယ်။

architecture အရတော့

Admin Mobile နဲ့ Client Mobile သွားမယ်။

Firebase Realtime Database

JSON တစ်ခုပဲ။

Flutter မှာ ဘယ်လိုလုပ်ကြမလဲ?

install firebase_core in flutter add init code in main()

firebase console မှာ realtime database တစ်ခု create လုပ်။ test mode ဖွင့်ထား နောက်ပိုင်းမှာ Locked Mode ဖွင့်ထားမယ်။ client တွေစီက write request တွေ လက်မခံပဲ ကိုယ်သတ်မှတ်တဲ့ server က လာတဲ့ operation တွေကိုပဲ လက်ခံမယ့် သဘော။

install firebase_database package in flutter

FirebaseDatabase database = FirebaseDatabase.instance;
DatabaseReference ref = FirebaseDatabas.instance.ref("users/123");
// write , overwrite all key and value
await ref.set(
    {
        "name": "John"
    }
);

// update name, leave age, and sex with old data
await ref.set(
    {
        "name": "John"
    }
);

/* နားမလည်တာက path ဆိုတာ ဘာလဲ? */
/* JSON Key ကို ပြောချင်တာလား ? */
DatabaseReference ref = FirebaseDatabas.instance.ref("users");
await ref.update({
    "123/age": 19,
    "123/address/line1": "1 Mountain View"
});

/* listening data changes */
/* make sure closet level of data , don't listen root database instance */
DatabaseReference starCountRef = FirebaseDatabase.instance.ref("posts/$postId/starCount");
starCountRef.onValue.listen((DatabaseEvent event){
    final data = event.snapshot.value;
    updateStarCount(data);
    /* 
        event.snapshot.exists => true or false
        event.snapshot => may be null
    */

});

/* read once from remote / local */
final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get(); // get from remote, if not find local 
if(snapshot.exists){
    print(snapshot.value);
}
else{
    print("No data availbale");
}

// တကယ်ကို တစ်ခါတည်း ဖတ်မှာ၊ ပြီးတော့ local ကနေ ချက်ခြင်းလိုချင်တာမျိုး
final event = await ref.once(DatabaseEventType.value);
final username = event.snapshot.value?.username ?? "Anonymous";

// insert and updating
void writeNewPost(String uid, String username, String picture, String title, String body){
    final postData = {
        'author' : username,
        'uid' : uid,
        'body' : body,
        'title' : title,
        'starCount' : 0,
        'authorPic' : picture,
    };

    // Get a key for a new post
    // .push() create new child
    // .key retrieve of newly created child
    // ဒီ key ကိုပဲ user-post မှာ ပြန်သုံးမယ်။
    final newPostKey = FirebaseDatabase.instance.ref().child('posts').push().key;
    // update in two paths
    final Map<String, Map> updates = {};
    /* u know, it's not linking, it's storing duplicate things */
    updates['/posts/$newPostKey'] = postData;
    updates['/user-posts/$uid/$newsPostKey'] = postData;
    // ဒါက update အားလုံး failed ရင် failed ဒါမှမဟုတ် အကုန် success ပြမယ်။ actomicity ဆိုပါတော့ ။
    return FirebaseDatabase.instance.ref().update(updates);

    /* set / update callback functions */
    FirebaseDatabase.instance
        .ref('users/$userId/email')
        .set(updateEmailAddress)
        .then((_){
            // data saved successfully
        })
        .catchError((error){
            // The write failed ...
        })
    );

    // ဖျတ်မယ်ဆိုရင် delete()

    // auto increment သုံးချင်ရင်
    // ServerValue.increment(1);
    updates["posts/$postId/startCount"] = ServerValue.increment(1);
}

data စပြီး ဘယ်လို ဖတ်မလဲ?

လက်ရှိ record တစ်ခုတည်းကို ဖတ်ရုံပဲ။

name first_digit second_digit final_digit

data structure ကို တက်နိုင်သမျှ nested မသုံးပဲ flat ဖြစ်နိုင်သမျှ ဖြစ်အောင်ထား။

read တွေ write တွေက auth user တွေကိုပဲ ပေးလုပ်တာ များတယ်။ ဒီတော့ firebase auth ပါ လိုလာမယ်။

String, boolean, int , double, Map, List သုံးလို့ရမယ်။

{

}

တက်နိုင်သမျှ key value တွေသာသုံး

Data Structure for mahar-by-ksmt

အကုန်လုံးက Json Object တစ်ခုတည်းမှာ ထည့်ထားမှာ ဆိုတော့ level one ရဲ့ key တွေက Table သဘောမျိုး ဖြစ်နေမယ်။ array မသုံးပဲ key->value pair တွေချည်းသုံးတာ ကောင်းမယ်။ undefined index မဖြစ်တော့ပဲ key မရှိတောင် null ဖြစ်နေတာမျိုး။

ER Diagram

အဓိက သုံးမယ့် Entity တွေက

  • User
  • Intake

လောလောဆယ်တော့ ဒီ (၂) ခုပဲ။

User ကလည်း လောလောဆယ် Firebase Auth မသုံးသေးတော့ အိုကေတယ်။

အိုကေ ဒီတော့ Intake ကိုပဲ စဉ်းစားကြတာပေါ့။

Intake

  • _id
  • date
  • time
  • digit
  • name : Intake Name Object

တစ်ခုရှိတာက name ကလည်း မျိုးစုံ ဖြစ်နိုင်တယ်။

IntakeName

  • _id
  • name

User

  • _id
  • email
  • name
  • profile_pic_url

Bet

  • _id
  • digit
  • intake
  • user

ဒါကိုပဲ array တစ်ခုတည်းမှာ သိမ်းထားရင် ရပြီ။

Lucky

  • _id
  • digit
  • intake

ဒါလည်း အိုကေပြီ ထင်တယ်။

Data တိုင်းကတော့ store လုပ်ပြီးသွားပြီ။

Report အပိုင်းနဲ့ အလျော်အစားပဲ ကျန်မယ်။

ပထမ Report အတွက်က Aggregrate Function နဲ့ Filter တွေ လိုမယ်။ နောက်ပြီး pagination ဘယ်လိုလုပ်လဲ ကြည့်ရမယ်။ data တွေကတော့ နေရာအစုံမှာ duplicate လုပ်မယ်ဆိုတာ သိထားပါ။

ဒါမှ မဟုတ် aggregrate မလုပ်ပဲ တိုက်ရိုက်တွက်ထားတာက ဒီဘက်မှာ ပိုအဆင်ပြေမလား?

ပထမဆုံး ကြည့်မှာက အခု intake မှာ ဘယ်ဂဏန်းတွေ ဘယ်လောက် ထိုးထားပြီးပြီလဲ?

{
    "bet_reports" : {
        "_intakeId" : {
            "0" : 20,
            "1" : 10,
            ...
            "99" : 150,
            "sum" : 2000,
            "lucky" : 55,
            "win" : 1500,
            "lose" : 500
        }
    }
}

path ကလည်း ဒါမျိုး ဖြစ်သွားမယ်။

bet_reports/_intakeId

realtime လည်း ဖြစ်မယ်။ နောက်ပြီး report လည်း ရေးထားပြီးသားဖြစ်မယ်။

ဒီအပေါ်က data ရရင် win / lose အခြေအနေကိုလည်း တိုက်ရိုက် ထုတ်ပြနိုင်နေမယ်။

Provider -> Data Source တွေ ကြားထဲမှာပဲ stream သုံးပြီး Provider နဲ့ UI ကြားမှာတော့ NotifyListener အရင်အတိုင်း သွားကြတာပေါ့။

Provider <-> Repository ကြားမှာ က Clean Stream ဆိုလိုတာက Entity တွေပဲ သယ်ယူပို့ဆောင် လုပ်မယ်။ Repository <-> DataSource ကြားမှာလည်း အတူတူပဲ Clean Stream ကိုပဲ ဆက်သုံးမယ်။ ဒါပေမယ့် ဒီမှာ Failure ပြန်ကောင်း ပြန်လာမယ်။ DataSource <-> Firebase ကြားမှာတော့ Raw Stream ကို သုံးမယ်။ Raw Stream က ရလာတဲ့ Data ကို Clean လုပ်ပြီးမှ Repository အတွက် Clean Stream ကနေ Entity တွေ ပို့ပေးမယ်။ အဲ့မှာ Repository ကနေ Usecase က တဆင့် Data တွေကို Stream နဲ့ ထပ်ပို့ပေးမယ်။

abstract class MaharRepository{
    /* User Login အပိုင်းက UI တွေလည်း ပါတာဆိုတော့ ဘယ်လိုလုပ်ကြမလဲ? Provider နဲ့ UI အကြားမှာပဲ ထားမလား? */
    Future<Stream<Intake>, Failure> getCurrentIntake({required String accessToken});
    // ဒါက admin အတွက်ပဲ။
    Future<String, Failure> setCurrentIntake({required String accessToken, required Intake intake});

    Future<List<Intake>, Failure> getIntakeListByDate({required String accessToken, required Date date});
    Future<List<Gift>, Failure> getGiftListByDate({required String accessToken, required Date date});
}

အခု အခြေအနေအရတော့ Repository က အဓိက အကျဆုံးပဲ။

ပြီးမှ Usecase ပေါ့ ။

Outline ရဖို့က Repository ရေးရင် ရပြီ။ အမှန်ကတော့ Use Case တွေ တန်းစီပြီး ချရေးရမှာ။

အိုကေ UseCase ဆိုပါတော့

ဆိုတော့ကာ လေလေ

Flatering the data structure

တက်နိုင်သမျှ nest နေကြတာ ကျွန်တော်တို့အတွက် Google က အကြံပေးတဲ့ Flat Datastructure က အတော်လေး ထူးဆန်းတယ်။

List ထဲကို data append လုပ်မယ်

DatabaseReference postListRef = FirebaseDatabase.instance.ref("posts");
DatabaseReference newPostRef = postListRef.push();
newPostRef.set({

});

Children တွေရဲ့ Event တွေကို ဘယ်လို listen လုပ်ကြမလဲ

collection တစ်ခုလုံးကို Listen လုပ်တာ မလုပ်ပဲ။ append လုပ်တာ။ update လုပ်တာ။ remove လုပ်တာလောက်ကိုပဲ တိတိကျကျ listen လုပ်ထားရင် ပိုပြီး effecient ဖြစ်တာပေါ့။

nested json တွေ အကုန်လုံးက path အနေနဲ့ သွားတာ။

final commentRef = FirebaseDatabase.instance.ref("post-comments/$postId");
commentRef.onChildAdded.listen((event){
    // a new comment has been added
});
commentRef.onChildChanged.listen((event){
    // a comment has changed
});
commentRef.onChildRemoved.listen((event){
    // a comment has been removed
});

ဒါက sorting အပိုင်း

final myUserId = FirebaseAuth.instance.currentUser?.uid;
final topUserPostsRef = FirebaseDatabase.instance.ref("user-posts/$myUserId").orderByChild("starCount");

for nested json

{
    "posts":{
        "ts-functions":{
            "metrics":{
                "views" : 100,
                "likes" : 25000
            },
            "title": "Why we should use TypeScript?",
            "description" : "blah blah blah blah "
        },
        "node-js":{
            "metrics":{
                "views" : 502,
                "likes" : 65203
            },
            "title": "Node : The fall of JS",
            "description" : "blah blah blah blah "
        }
    }
}
final mostViewedPosts = FirebaseDatabase.instance.ref("posts").orderByChild("metrics/views");

// orderByChild
// orderByKey
// orderByValue

/* We can use only one order by cretia */

Filter ဘယ်လိုလုပ်မလဲ?

// limitToFirst
// limitToLast
// startAt
// startAfter
// endAt
// endBefore
// equalTo

final recentPostsRef = FirebaseDatabase.instance.ref('posts').limitToLast(100);

** ရှာတာ ဖွေတာ မရဘူး *** list နဲ့ ဆွဲထုတ်ရင်တော့ ရမယ်။

orderBy မှာ date ဘာညာသာရကာ သုံးလဲ sorting အတွက်ပဲ။ အိုကေ sorting အတွက် လုပ်တဲ့ နေရာမှာ where clause လို့ သဘောထားလို့တော့ ရမယ်။ မရဘူးပဲ။ where clause မှာက equal to ပါတယ်။ sorting / orderBy မှာက field name တစ်ခုပဲ ပါတာ။

filter မှာတော့ equalTo ဆိုတဲ့ emthod ပါတယ်။ ကိုယ်လိုချင်တဲ့ where clause သုံးလို့ရမလား ကြည့်ရအောင်။

ရပြီ

dinosaursRef.orderByChild("height").equalTo(25); 

ဆိုတော့ကာ orderByChild နဲ့ equalTo ကို သုံးပြီး လိုချင်တဲ့ row အတိအကျကို filter လုပ်လို့ရမယ်။

pagination လိုချင်ရင် offset အနေနဲ့ .startAfter limit အနေနဲ့ .limitToFirst

ဆိုပါတော့ ကိုယ်က

user ရဲ့ တစ်ရက်စာ bet list ကို ထုတ်ကြည့်ချင်တယ်။

သိမ်းထားတဲ့ ပုံစံက ဒါမျိုး ဖြစ်မယ်။

user-bets

{
    "user-bets" : {
        "user_id" : {
            "intake_id": {
                "bet_id" : {
                    // bet object
                },
                "bet_id2" : {
                    // bet object
                }
            }
        }
    }
}

@ input

  • userId
  • date

ပြန်လာရမှာက List


Written on December 31, 2022