Android

Firebase, Bài 4.2: Hướng dẫn chuyển đổi sang Firebase Realtime Database từ SQL Database

Sau khi bạn đã có cái nhìn tổng quát và đã tính toán được hướng đi của mình, thì bài viết này sẽ tiếp tục cung cấp thêm lí thuyết về cách query cũng như insert, update, remove dữ liệu trên FRD tương ứng với SQLD mà bạn đã quá thông thạo. Vui lòng lưu ý là không phải mỗi SQLD Table chỉ có một cách chuyển đổi duy nhất sang một FRD (xin xem lại bài trước). Việc lựa chọn cấu trúc nào là tùy vào ý tưởng của bạn và mục đích của CSDL đó, cũng như trình độ và kinh nghiệm thao tác với FRD mà bạn có được.

FirebaseRealtimeDatabase

Trước khi tiếp tục thì tôi sẽ đưa ra cái bảng SQLD “huyền thoại” trong bài trước để bạn tiện theo dõi:

TABLE NAME: EXAMPLE_DB

 No Organisations Website_addresses Headquarter_location
 1 EITGUIDE http://eitguide.com  Vietnam
 2 GOOGLE http://www.google.com US
 3 APPLE http://www.apple.com US

Và CSDL của FRD sẽ được chọn như sau:

5. Query dữ liệu

Nếu tôi tìm lọc đối tượng có tên là “Google” trên FRD vừa nêu thì sẽ không hề khó khăn, vì tôi đã định vị được “google” nằm trong “organisation” rồi. Vì vậy, ở đây, để lấy địa chỉ website của “google” ra thì tôi chỉ việc lấy đối tượng (FIR)DatabaseReference trỏ vào “organisations” và trỏ tiếp vào “google”, mà lấy thông tin “website” ra mà thôi. Còn trong SQLD thì câu Schema của bạn sẽ là “SELECT Website_addresses FROM EXAMPLE_DB WHERE (Organisations = ‘GOOGLE’)”.

Nhưng nếu tôi muốn làm ngược lại, muốn lấy tên Organisation ra khi biết Website_addresses rồi, thì câu Schema trong SQLD của tôi không quá khác biệt. Tuy nhiên, đối với FRD thì các bạn “mới học” sẽ gặp ít nhiều khó khăn, bởi lẽ trường “website” nằm trong trường mang tên đối tượng, tức là “eitguide”, “google” và “apple”. Vậy thì làm thế nào?

Là người chuyên nghiệp, anh David East sẽ sử dụng ordering query. Chẳng hạn ở đây, anh ấy sẽ làm theo hướng bên dưới. Vì các hàm tương tự nhau cho Android, iOS và Web nên tôi sẽ chỉ trình bày vắn tắt:

Ngoài hàm orderByChild/queryOrderedByChild, chúng ta còn có orderByKey/queryOrderedByKey – mặc định là các children sẽ được sắp xếp theo orderByKey, orderByValue/queryOrderedByValue, limitToFirst(numberOfRange)/queryLimitedToFirst, limitToLast(numberOfRange)/queryLimitedToLastqueryStartingAtValue/startAt, queryEndingAtValue/endAtqueryEqualToValue/equalTo để giới hạn số lượng đối tượng cũng như dò đúng đối tượng đó.

Tuy nhiên, cá nhân tôi không thích lọc trực tiếp qua các hàm trong Firebase SDK libs vì 2 lí do sau: Một là bạn chỉ được gọi order được 1 lần, do đó việc bạn gọi thêm orderByChild(“hq_location”) tại webRef là điều không được phép. Theo anh David East thì bạn phải làm thêm một trường phụ nữa là “website_hq” và cho query trường thông tin đó. Tuy nhiên, điều này là không hề dễ với các CSDL lớn. Hai là để order theo child nào thì phải đảm bảo các children object phải có thuộc tính đó, ví dụ ở đây thì “eitguide”, “google” và “apple” đều cần có “website” property, nếu lỡ một tên mới xuất hiện như “samsung” và không có thuộc tính đó thì sẽ có thể phát sinh các tình huống không mong muốn.

Do vậy, tôi khuyến nghị bạn lọc dữ liệu ở thiết bị khách (client), tức là trong ứng dụng Android, iOS hoặc Web với các hàm bạn tự dựng từ Object class mà bạn tạo. Ví dụ ở đây, tôi sẽ lấy các children của orgRef ra thông qua đối tượng (FIR)DataSnapshot, cast chúng thành tập hợp đối tượng, và đem lọc giá trị qua thuộc tính của từng đối tượng qua hàm getChildren() với Android, children với iOS và với Web là forEach(child). Cụ thể:

6. Table joining.

Nếu bạn có nhiều bảng SQLD thì việc liên kết các bảng lại là điều ít nhiều phải có. Chẳng hạn, bấy giờ tôi có thêm một bảng sau

Organisations CEO
EITGUIDE Nguyễn Nghĩa
GOOGLE Larry Page
APPLE Tim Cook

Bây giờ, giả sử sếp của bạn yêu cầu “Hãy tìm cho mình tên của các ông CEO của các cty có trụ sở ở US”. Thoạt nhìn thì bạn sẽ nói ngay đó là 2 ông LarryPage – Google và Tim Cook – Apple rồi. Nhưng thực ra trong suy nghĩ của bạn đã có hành động Join các Tables lại với nhau dù bạn có để ý hay không. Ở SQLD thì ta  JOIN các bảng. Ở đây đương nhiên là bạn sẽ JOIN chúng thành một cái bảng thứ 3 giống như sau:

Organisations Headquarter_location CEO
EITGUIDE Vietnam Nguyễn Nghĩa
GOOGLE US Larry Page
APPLE US Tim Cook

Và bạn chỉ đơn giản là tìm kiếm trên bảng mới đó mà thôi. “Để xem nào, tìm trên cột Headquarter_location coi có tên nào ở US, xong chiếu qua cột CEO mà lấy tên ra…” – đó chính là thao tác của bạn.

Tuy nhiên, với FRD thì bạn làm thế nào? Giả sử bạn phải bổ sung trường CEO sau gần 2 tháng với số lượng dữ liệu trong phần “organisations” lên tới 3000. Không lẽ bạn update từng cái? Nên bạn sẽ thêm 1 node ngang hàng với organisations như dưới đây:

Anh David East đưa ra giải pháp thêm 1 node phụ nữa. Trong trường hợp này, nếu làm theo hướng dẫn của anh ấy thì ta lại “cồng kềnh hóa” CSDL của chúng ta như sau:

Nhìn có vẻ dễ tìm đấy, vì ta chỉ cần trỏ vào “hq_location_and_ceos”/”US” là ra ngay tức khắc. Tuy nhiên, nếu sếp của bạn hứng lên ra thêm một yêu cầu khác và khắt khe hơn thì không lẽ bạn lại làm thêm một node nữa, gây nên tình trạng dư thừa dữ liệu hoàn toàn không đáng có. Tất nhiên, không thể phủ nhận độ nhanh và dễ dàng của việc thêm 1 node trung gian đó, nhưng theo tôi, điều này chỉ thích hợp khi bạn làm CSDL ban đầu để chuẩn bị đưa vào hoạt động, hoặc sau này, bạn cho phép các thiết bị khách thoải mái làm node mới thì e rằng CSDL của bạn dễ trở thành một mới hỗ lốn do hoạt động spam quá nhiều từ các thiết bị khách.

Do đó, trở lại với màn query dữ liệu, thì bạn hãy để ý lại CSDL tôi đưa ra:

Theo hướng bạn Join các Tables trong SQLD thì bạn có để ý rằng cột Organisation của mình mang tính unique không? Tức là nếu bạn không đặt PRIMARY KEY cho cột No thì vẫn có thể dùng cột Organisations làm PRIMARY KEY vẫn được. Và trên FRD cũng vậy. Đơn giản là bạn trỏ vào từng child của “organisations”, tìm “hq_location” của nó, xong trở ngược lên lấy key và quay sang node “ceos” để lấy tên các Giám đốc điều hành ra.

7. Add, remove và update dữ liệu

Như tôi đã giới thiệu trong Bài 2.1, nếu bạn set value với 1 Object mới, thì đương nhiên nó sẽ phải ứng với 1 key. Nếu key đó (được bạn đặt theo ý hay dùng hàm push() hoặc childByAutoId()) chưa tồn tại thì FRD sẽ tạo một node mới, và đó là thao tác add. Còn nếu key đó đã tồn tại, thì Object mới sẽ thay thế Object cũ làm value cho key đó, tức là thao tác edit, theo nguyên tắc overwrite: Chưa có thì tạo mới, có rồi thì cập nhật/thay thế. Còn thao tác remove thì đơn giản rồi.

Như vậy, bạn có thể thấy phần FRD key đóng vai trò tương đương với Primary Key của SQLD, mỗi FRD key sẽ phải unique (độc nhất), không được trùng. Điều này đơn giản tương tự như nhà mạng chỉ phát hành mỗi đầu số điện thoại cho một thuê bao duy nhất. Vậy key quan trọng như thế nào? Có lẽ bạn đã hiểu được tầm quan trọng của nó trên FRD. Còn ở phần ứng dụng trên thiết bị khách truy cập vào CSDL, nó sẽ là căn cứ để bạn cập nhật danh sách dữ liệu, tức là thêm một dòng mới trong ListView, RecyclerView, UITableView hay <ul><li> vào vị trí nào, thay đổi nội dung của dòng nào, và xóa dòng nào ra khỏi cái danh sách đó.

Như vậy, cũng tương tự như việc ta SET các dữ liệu mới cho một dòng thông qua value của PRIMARY KEY trong SQLD, ta cũng sẽ set các dữ liệu mới cho một đối tượng thông qua key trên FRD. Và đến đây thì tôi cũng tạm kết thúc phần hướng dẫn chuyển đổi từ SQLD sang FRD. Vui lòng lưu tâm một lần nữa là mọi hướng dẫn chúng tôi đưa ra đều chỉ mang tính tham khảo và được tối ưu hóa cho CSDL mà tôi đưa ra. Còn đối với CSDL của các bạn thì có thể sẽ cần được cấu trúc theo hướng khác, được query theo hướng khác sẽ nhanh hơn. Vì vậy, việc thiết kế CSDL FRD phụ thuộc vào bản chất của SQLD đó, sự mong đợi của bạn, cũng như trình độ và kinh nghiệm thao tác với FRD mà bạn có được.

9 thoughts on “Firebase, Bài 4.2: Hướng dẫn chuyển đổi sang Firebase Realtime Database từ SQL Database”

  1. Anh cho em hỏi chút, em muốn dùng firebase để lưu dữ liệu của người dùng, chỉ lưu đơn giản như bookmark chẳng hạn (không phải ứng dụng realtime kiểu chat app), thì có dùng firebase được không. Tại em thấy firebase free giới hạn số user online cùng lúc là 100 thì phải (cái này em cũng không hiểu lắm), và nếu tạo ứng dụng realtime kiểu chat app với 1000 user thì sao ạ.

    1. Dùng FRD để lưu thông tin như bookmark: Vô tư, việc sử dụng CSDL ra sao là tùy bạn mà. Số online users tại một thời điểm là 100 đối với gói miễn phí. Các gói miễn phí có mức mặc định thấp nhất là 10 ngàn và có thể gia tăng theo lượng phí mà bạn trả. Chi tiết bạn xem thêm ở đây: https://firebase.google.com/pricing/

    2. “chỉ lưu đơn giản như bookmark chẳng hạn”: Được chứ bạn, thoải mái luôn. Bạn có thể chỉ dùng http request gửi một lần lên Firebase và lấy dữ liệu về là được. Còn nếu muốn hỗ trợ 1000 users cùng lúc thì bạn phải chuyển sang gói có phí.

  2. Chào a, e đang làm 1 project dạng Web-app. với frontend là php và backend là java. e đang muốn viết firebase server dưới backend để push notification đến cho client đã đăng nhập thành công. nếu client offline thì sẽ lưu và gửi ở lần đăng nhập tiếp theo. Vậy e sẽ phải làm những gì ạ?

    1. Rất vui vì bạn biết bạn phải có server riêng để làm việc này, vì mỗi Firebase server không đủ để thực hiện thao tác gửi notification mang tính “tự động” như vậy, ít nhất là ở thời điểm hiện tại. Vì phần Cloud Messaging mình không viết nên mình chỉ nêu ngắn gọn, bạn có thắc mắc thêm thì vui lòng hỏi tiếp.

      Khi mỗi client đăng nhập vào Firebase thì client đó sẽ gửi deviceToken (và nếu có thể thì sẽ gửi luôn trạng thái online) lên server riêng của bạn và server của bạn phải lưu nó lại. Cách lấy deviceToken là gọi hàm Messaging.messaging().fcmToken với iOS, FirebaseInstanceId.getInstance().getToken() với Android và firebase.messaging.getToken() với Web.

      Từ server của bạn, bạn gửi yêu cầu send notification lên Firebase server. Thông báo này chứa nội dung và quan trọng nhất là deviceToken bạn muốn gửi notification xuống. Và Firebase server sẽ gửi notification của nó xuống client device kia.

    2. Tuy nhiên, với ý tưởng của bạn thì mình thấy bạn nên dùng firebase auth luôn, vì đã lỡ dùng firebase rồi thì dùng luôn cái auth. Nếu đăng nhập thành công thì bên client tự giải quyết luôn, không cần gửi notification nữa.

  3. Chào anh! em mới tìm hiểu về firebase thôi ạ,nên cho em hỏi một chút là: trong những ví dụ trên có thể thay text bằng ảnh động hay audio không ạ? Em cảm ơn ạ!!

    1. Được chứ, bạn chỉ cần push dữ liệu dạng String(byte[]) lên và lấy về, còn dưới client bạn giải mã như bình thường. Quan trọng là chỗ client thôi, còn dữ liệu cũng chỉ là file mà thôi.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.