Làm quen với PouchDB JavaScript Database cho Client
Trong những năm gần đây, ứng dụng web phía client đang ngày càng trở nên phức tạp. Cũng vì lẽ đó, trình duyệt cũng có ngày càng nhiều tính năng, hỗ trợ JavaScript tốt hơn với đủ thứ API như geolocation hay p2p communication.
Sự trỗi dậy của ứng dụng web cũng nâng cao nhu cầu lưu trữ cho client, và như vậy, tầm quan trọng của các JavaScript database như PouchDB cũng theo đó mà lên.
PouchDB là gì?
PouchDB là JavaScript database nguồn mở được phát triển dựa trên Apache CouchDB, được thết kế để chạy tốt trên trình duyệt.
Vậy JavaScript database là gì?
Nhìn chung, JavaScript database là một dạng JavaScript object, cung cấp cách thức (hay API) để nhập, xuất, và tìm kiếm dữ liệu. Trong thực tế, một JavaScript cơ bản, trống trải chính là dạng JavaScript database đơn giản nhất. Nếu quen thuộc với Meteor, bạn chắc đã nghe đến Minimong, một JavaScript database client-side bắt chước theo MongoDB API.
PouchDB là “hậu nhân” của CouchDB. Mục tiêu của PunchDB là mô phỏng CouchDB API với độ chính xác “gần như hoàn hảo” khi đang chạy trên trình duyệt hoặc trong Node.js.
PouchDB khác với các database khác như Minimongo vì nó (theo mặc định) không chỉ hoạt động trong bộ nhớ, mà còn “lén” dùng IndexedDB để lưu trữ. IndexedDB là API cấp thấp để lưu trữ lượng lớn dữ liệu có cấu trúc (structured data) trên phía client, và vẫn dùng được ngay cả khi page đã được refresh (tuy nhiên, dữ liệu lưu trữ cho trình duyệt này sẽ không dùng được cho các trình duyệt khác).
Các adapters khác nhau cho phép các bạn thay đổi underlying data storage layer (lớp lưu trữ dữ liệu tầng dưới).
Quan hệ với CouchDB
Vì là implementation của CouchDB, nên PunchDB sẽ mô phỏng API của CouchDB giống hết mức có thể.
Trong CouchDB, bạn sẽ truy xuất được tất cả tài liệu bằng API call sau
1
2
3
|
/ db / _all_docs ? include_docs = true
|
Còn trong PunchDB
1
2
3
|
db . allDocs ( { include_docs : true } )
|
PouchDB cho phép ứng dụng lưu trữ dữ liệu cục bộ nếu offline, và sau đó đồng bộ với CounchDB khi online trở lại.
Kế tiếp, hãy xem thử cách dùng PouchDB trong ứng dụng.
Cài đặt
Để bắt đầu sử dụng PouchDB bạn chỉ cần thêm PouchDB client library. Bạn có thể chọn standalone build, để dùng constructor PouchDB
rộng rãi trên object window
.
1
2
3
|
<script src = "https://cdn.jsdelivr.net/pouchdb/5.4.5/pouchdb.min.js" > </script>
|
hoặc, nếu đang dùng PouchDB trong môi trường Node.js/browserify/webpack, bạn có thể cài đặt với npm
.
1
2
3
|
$ npm install pouchdb -- save
|
Và rồi trong JavaScript của bạn:
1
2
3
|
var PouchDB = require ( 'pouchdb' ) ;
|
(Fun Fact: npm isntall pouchdb
cũng chạy tốt!)
Làm việc với PouchDB
tạo database
Tạo database trong PouchDB cũng đơn giản không kém việc call PouchDB constructor. Hãy thử tạo database tên ‘Movies’ nào.
1
2
3
|
var movies = new PouchDB ( 'Movies' ) ;
|
Sau khi chạy lệnh trên, bằng cách sử dụng thêm method info
(trả kết quả là Promise
), bạn có thể thấy được các thông tin cơ bản về database.
1
2
3
4
5
6
7
|
movies
. info ( )
. then ( function ( info ) {
console . log ( info ) ;
} )
|
Đoạn code trên sẽ cho ra output:
1
2
3
|
{ "doc_count" : 0 , "update_seq" : 0 , "idb_attachment_format" : "binary" , "db_name" : "Movies" , "auto_compaction" : false , "adapter" : "idb" }
|
Trường adapter
ám chỉ PouchDB đang ngầm dùng IndexedDB.
Làm việc với documents
PouchDB là database NoSQL, document-based, nên sẽ không có schema cứng nhắc, và bạn chỉ việc trực tiếp thêm JSON document. Hãy xem thử bạn có thể thêm, cập nhật, tìm kiếm hay xóa document như thế nào.
Tạo document
Bạn có thể tạo document mới bằng method put
1
2
3
4
|
// returns a promise
db . put ( doc , [ docId ] , [ docRev ] , [ options ] )
|
Các tham số trong ngoặc vuông không bắt buộc. Mỗi document có một trường _id
đi kèm để phân biệt.
Để tạo document mới trong database Moives
đã tạo, dùng đoạn code sau:
1
2
3
4
5
6
7
8
9
10
11
12
|
movies
. put ( {
_id : 'tdkr' ,
title : 'The Dark Knight Rises' ,
director : 'Christopher Nolan'
} ) . then ( function ( response ) {
console . log ( "Success" , response )
} ) . then ( function ( err ) {
console . log ( "Error" , err )
} )
|
Nếu thành công, bạn sẽ nhận phản hồi:
1
2
3
|
Success { ok : true , id : "tdkr" , rev : "3-f8afdea539618c3e8dceb20ba1659d2b" }
|
Đến đây, nếu call movies.info()
, bạn sẽ có {doc_count: 1}
cùng với các dữ liệu khác, cho thấy document ta vừa tạo đã được nhập.
Trường rev
trong phần phản hồi chỉ “revision” của document. Mỗi document có một trường có tên _rev
. Mỗi khi một document được update, trường _rev
của document được thay đổi. Mỗi revision chỉ đến mỗi revision trước đó của nó. PouchD luôn giữ history của mỗi document (như git).
Đọc Document
PouchDB cung cấp API method get
để tìm kiếm document bằng ID. Chạy:
1
2
3
4
5
6
7
8
9
10
|
movies
. get ( 'tdkr' )
. then ( function ( doc ) {
console . log ( doc )
} )
. catch ( function ( err ) {
console . log ( err )
} )
|
Sẽ cho kết quả
1
2
3
|
{ title : "The Dark Knight Rises" , director : "Christopher Nolan" , _id : "tdkr" , _rev : "3-f8afdea539618c3e8dceb20ba1659d2b" }
|
Cập nhật Document
Giả sử ta muốn thêm trường year
vào document. Bạn sẽ cập nhật document vừa tạo ở trên bằng:
1
2
3
4
5
6
7
8
9
10
11
|
movies
. get ( 'tdkr' )
. then ( function ( doc ) {
doc . year = "2012" // new field
console . log ( doc . _rev ) // doc has a '_rev' field
return db . put ( doc ) // put updated doc, will create new revision
} ) . then ( function ( res ) {
console . log ( res )
} )
|
Khi cập nhật document, bạn phải thêm trường _rev
.
Bạn sẽ thấy output tương tự trong console:
1
2
3
|
{ ok : true , id : "tdkr" , rev : "4-7a34189fb8f2e28fe08b666e699755b8" }
|
Ám chỉ revision mới của document.
Xóa Documents
Để xóa document trong PouchDB, chỉ việc set property _deleted
sang true
. Bạn có thể call .remove()
:
1
2
3
4
5
6
7
8
9
|
movies
. get ( 'tdkr' )
. then ( function ( doc ) {
return movies . remove ( doc ) // return the promise
} ) . then ( function ( res ) {
console . log ( "Remove operation response" , res )
} )
|
tương đương với
1
2
3
4
5
6
7
8
9
|
movies
. get ( 'tdkr' )
. then ( function ( doc ) {
doc . _deleted = true
return db . put ( doc )
} )
. then ( . . . )
|
Xóa database
Bạn có thể xóa database bằng cách call destroy()
lên db object.
1
2
3
4
|
// returns a promise
movies . destroy ( )
|
Bulk Operations (Thao tác đồng loạt)
Đến đay chúng ta đã làm việc với từng document riêng biệt trong PouchDB. Tuy nhiên, PouchDB còn cung cấp thêm API để làm việc với một loạt document. PouchDB cũng cấp hai phương pháp thực hiện thao tác hàng loạt – bulkDocs()
để viết hàng loạt và allDocs()
để đọc hàng loạt.
Method bulkDocs()
thì lại khá đơn giản: lựa chọn một dãy document bạn muốn và nhập vào database.
Nhập nhiều documents
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// Returns a promise
movies . bulkDocs ( [
{
_id : 'easy-a' ,
title : "Easy A" ,
// other attribues
} ,
{
_id : 'black-swan' ,
title : 'Black Swan' ,
// ...
}
] )
|
Phản hồi mẫu:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
[
{
"ok" : true ,
"id" : "easy-a" ,
"rev" : "1-84abc2a942007bee7cf55007cba56198"
} ,
{
"ok" : true ,
"id" : "black-swan" ,
"rev" : "1-7b80fc50b6af7a905f368670429a757e"
}
]
|
Nếu bạn muốn nhập nhiều document, dùng bulk API vẫn tốt hơn là nhiều request put()
. Thao tác đồng loạt thường nhanh hơn thao tác đơn lẻ, vì được kết hợp vào giao dịch duy nhất (với local IndexedDB/WebSQL store) hoặc một HTTP request duy nhất (với remote CouchDB server).
Tìm kiếm nhiều Documents
Để đọc nhiều document, PouchDB cung cấp method allDocs()
1
2
3
4
5
6
7
8
|
// nếu thiếu {include_docs: true}, bạn chỉ nhận kết quả ID của doc
movies
. allDocs ( { include_docs : true } )
. then ( function ( docs ) {
console . log ( docs )
} )
|
Thật nhanh và hữu dụng. Trích từ tài liệu của PouchDB:
allDocs() là ngôi sao sáng bị khuất lấp trong thế giới PouchDB. Nó không chỉ trả kết quả document theo thứ tự, mà còn theo thứ tự đảo ngược nữa, lọc theo _id, cắt xén với các thao tác “greater than” (lớn hơn) và “less than” (nhỏ hơn) trên _id,…
Theo mặc định, các document được trả theo thứ tự _id
tăng dần. Bạn có thể chỉ định {descending: true}
để đảo ngược thứ tự.
1
2
3
4
5
6
7
8
|
movies
. allDocs ( {
include_docs : true ,
descending : true
} )
. then ( . . . )
|
Bạn cũng có thể chỉ định tham số startkey
và endkey
để nhận document trong một khoảng nhất định. Ví dụ, để nhận tất cả movies (phim) có _id
bắt đầu với ‘a’, hay ‘b’, bạn có thể chạy truy vấn sau:
1
2
3
4
5
6
7
8
9
10
|
movies
. allDocs ( {
include_docs : true ,
startkey : 'a' ,
endkey : 'c'
} )
. then ( console . log )
. catch ( console . log )
|
Các tham số startKey
và endKey
được sử dụng cụ thể cho các API được đánh số.
Làm việc thời gian thực với ChangeFeeds
Chúng ta đã nói về cách sử dụng của PouchDP sử dụng trường _rev
để theo dõi revision, với mỗi revison chỉ về revision trước đó. Cả PouchDB và CouchDB đều dùng chuỗi revision này để sao chép database.
Tuy nhiên, việc thực hiện thuật toán sao chéo này còn có thuận lợi là bạn có thể xem lịch sử database, cho phép bạn trả lời các câu hỏi như
- Những thay đổi nào áp dụng đến database kể từ một thời điểm cụ thể?
- Những thay đổi nào áp dụng đến một tài liệu cụ thể?
Đây là lúc bạn cần dùng đến API changes()
.
Để truy xuất tất cả thay đổi từ đầu đến cuối:
1
2
3
4
5
6
7
8
|
db . changes ( {
since : 0 ,
include_docs : true
} ) . then ( function ( changes ) {
console . log ( changes )
} ) . catch ( . . . )
|
Tuy nhiên, trong ứng dụng web bạn thường chú ý đến những thay đổi đến database sau lần page load ban đầu hơn, để có thể thay đổi UI cho phù hợp. Bộ dôi PouchDB/CouchDB cũng hỗ trợ rất tối với live change feed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
db
. changes ( {
since : 'now' ,
live : true ,
include_docs : true
} )
. on ( 'change' , function ( change ) {
// Đây là chỗ điều chỉnh UI, dựa trên thay đổi trên database.
// change.id chứa id của id, change.doc chứa doc
if ( change . deleted ) {
// đã xóa document
} else {
// document was added/modified
}
} )
. on ( 'error' , function ( err ) {
// xử lý errors
} )
|
Bạn có thể xem thử demo tại đây.
Đồng bộ hóa: Dữ liệu PouchDB không chỉ nằm ở trình duyệt
Đa số ứng dụng không chỉ lưu trữ dữ liệu trên trình duyệt mà cần phải lấn sang cả back-end, để bạn có thể dùng PouchDB để lưu dữ liệu cục bộ, nhưng đồng bộ hóa với một back-end CouchDB instance, từ đó data có thể dùng được ở bất cứ đâu, không chỉ trong một trình duyệt cụ thể.
PouchDB cung cấp một API rất đơn giản để thực hiện “cả mớ” việc trên. Giả sử, bạn đã set up một remote CouchDB database, việc đồng bộ giờ đây chỉ gói gọn trong hai dòng lệnh JavaScript.
1
2
3
4
5
6
7
|
// local database, nằm trong IndexedDB store của trình duyệt
var localDB = new PouchDB ( 'mylocaldb' )
// remote CouchDB
var remoteDB = new PouchDB ( 'http://localhost:5984/myremotedb' )
|
Bạn có thể sao chép các thay đổi cục bộ đến remote DB bằng
1
2
3
4
5
6
7
8
9
10
|
localDB
. replicate
. to ( remoteDB )
. on ( 'complete' , function ( ) {
// local changes replicated to remote
} ) . on ( 'error' , function ( err ) {
// error while replicating
} )
|
Tuy nhiên, vì nhiều người dùng có thể truy cập được vào cùng một database, nên sẽ tiện hơn nếu bạn có thể đồng bộ thay đổi từ remote DB đến trình duyệt. PouchDB cũng “xử gọn” vấn đề này luôn.
Quá trình đồng bộ hai chiều có thể được thực hiện bằng dòng JavaScript sau:
1
2
3
4
|
// sao chép một lần
localDB . sync ( remoteDB ) ;
|
Hoặc với đồng bộ trực tiếp:
1
2
3
4
|
// Liên tục đồng bộ hóa thay đổi ngay khi xảy ra
localDB . sync ( remoteDB , { live : true } )
|
Nhiều hơn thế nữa…
Đằng sau PouchDB là một hệ sinh thái plugins và framework adaptors phát triển không ngừng nghĩ để hỗ trợ người dùng tốt nhất có thể. Đồng thời, khi làm việc với PouchDB, bạn có thể dùng kèm tiện ích chrome PouchDB Inspector, mang đến GUI đạp mắt cho database của bạn.
Sitepoint
- Hack tài khoản Facebook, Twitter... trong nháy mắt
- Điều cần biết về ERP
- Lập trình viên: Một nghề chân chính, một nghề cần vinh danh?
- Series Bảo Mật Nhập Môn – Bảo mật cơ bản cho developer
- 8 hàm CSS siêu hay
- 6 sự thật phũ phàng không phải ai trong ngành lập trình cũng biết
- Vì sao một số người lại không thể thành công?
- Những sai lầm junior developer thường mắc phải và cách phòng tránh
- Cuốn sách Oreilly Building on SugarCRM Jul 2011
- Microsoft cập nhật tính năng project references trong TypeScript 3.0
- Các xu thế chi phối sự chuyển dịch của di động năm 2014
- Bị Apple từ chối, chàng sinh viên này không hề nản chí mà còn dành 3 tháng để tái thiết kế lại Apple Music
DVMS chuyên:
- Tư vấn, xây dựng, chuyển giao công nghệ Blockchain, mạng xã hội,...
- Tư vấn ứng dụng cho smartphone và máy tính bảng, tư vấn ứng dụng vận tải thông minh, thực tế ảo, game mobile,...
- Tư vấn các hệ thống theo mô hình kinh tế chia sẻ như Uber, Grab, ứng dụng giúp việc,...
- Xây dựng các giải pháp quản lý vận tải, quản lý xe công vụ, quản lý xe doanh nghiệp, phần mềm và ứng dụng logistics, kho vận, vé xe điện tử,...
- Tư vấn và xây dựng mạng xã hội, tư vấn giải pháp CNTT cho doanh nghiệp, startup,...
Vì sao chọn DVMS?
- DVMS nắm vững nhiều công nghệ phần mềm, mạng và viễn thông. Như Payment gateway, SMS gateway, GIS, VOIP, iOS, Android, Blackberry, Windows Phone, cloud computing,…
- DVMS có kinh nghiệm triển khai các hệ thống trên các nền tảng điện toán đám mây nổi tiếng như Google, Amazon, Microsoft,…
- DVMS có kinh nghiệm thực tế tư vấn, xây dựng, triển khai, chuyển giao, gia công các giải pháp phần mềm cho khách hàng Việt Nam, USA, Singapore, Germany, France, các tập đoàn của nước ngoài tại Việt Nam,…
Quý khách xem Hồ sơ năng lực của DVMS tại đây >>
Quý khách gửi yêu cầu tư vấn và báo giá tại đây >>