Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
2.1: Model data dasar
Aplikasi contoh ini menyoroti konsep model data DynamoDB berikut:
-
Tabel – Di DynamoDB, tabel adalah kumpulan item (yaitu, catatan), dan setiap item adalah kumpulan pasangan nama-nilai yang disebut atribut.
Dalam Tic-Tac-Toe contoh ini, aplikasi menyimpan semua data game dalam sebuah tabel,
Games
. Aplikasi ini membuat satu item dalam tabel per game dan menyimpan semua data game sebagai atribut. Sebuah tic-tac-toe permainan dapat memiliki hingga sembilan gerakan. Karena tabel DynamoDB tidak memiliki skema jika hanya kunci primer yang merupakan atribut yang diperlukan, aplikasi dapat menyimpan sejumlah atribut yang bervariasi per item game.Tabel
Games
memiliki kunci primer sederhana yang dibuat dari satu atribut,GameId
, jenis string. Aplikasi ini menetapkan ID unik untuk setiap game. Untuk informasi selengkapnya tentang kunci primer DynamoDB, lihat Kunci primer.Saat pengguna memulai tic-tac-toe permainan dengan mengundang pengguna lain untuk bermain, aplikasi akan membuat item baru dalam
Games
tabel dengan atribut yang menyimpan metadata game, seperti berikut ini:-
HostId
, pengguna yang memulai game. -
Opponent
, pengguna yang diundang untuk ikut bermain. -
Pengguna yang mendapat giliran bermain. Pengguna yang memulai game akan bermain terlebih dahulu.
-
Pengguna yang menggunakan simbol O di papan. Pengguna yang memulai game menggunakan simbol O.
Selain itu, aplikasi membuat atribut bersambung
StatusDate
, menandai status game awal sebagaiPENDING
. Tangkapan layar berikut menampilkan contoh item seperti yang muncul di konsol DynamoDB:Seiring game berlangsung, aplikasi menambahkan satu atribut ke tabel untuk setiap langkah game. Nama atribut adalah posisi papan, misalnya
TopLeft
atauBottomRight
. Misalnya, sebuah langkah mungkin memiliki atributTopLeft
dengan nilaiO
, atributTopRight
dengan nilaiO
, dan atributBottomRight
dengan nilaiX
. Nilai atribut adalahO
atauX
, tergantung pada pengguna mana yang melangkah. Contoh, pertimbangkan papan berikut ini. -
-
Atribut nilai bersambung – Atribut
StatusDate
mengilustrasikan atribut nilai bersambung. Dalam pendekatan ini, alih-alih membuat atribut terpisah untuk menyimpan status game (PENDING
,IN_PROGRESS
, danFINISHED
) dan tanggal (ketika langkah terakhir dilakukan), Anda menggabungkannya sebagai atribut tunggal, misalnyaIN_PROGRESS_2014-04-30 10:20:32
.Aplikasi kemudian menggunakan atribut
StatusDate
dalam membuat indeks sekunder dengan menentukanStatusDate
sebagai kunci urutan untuk indeks. Manfaat penggunaan atribut nilai bersambungStatusDate
diilustrasikan lebih lanjut dalam indeks yang akan dibahas selanjutnya. -
Indeks sekunder global – Anda dapat menggunakan kunci primer tabel,
GameId
, untuk mengkueri tabel secara efisien guna menemukan item game. Untuk mengkueri tabel pada atribut selain atribut kunci primer, DynamoDB mendukung pembuatan indeks sekunder. Dalam contoh aplikasi ini, Anda membuat dua indeks sekunder berikut:-
HostId- StatusDate -indeks. Indeks ini memiliki
HostId
sebagai kunci partisi danStatusDate
sebagai kunci urutan. Anda dapat menggunakan indeks ini untuk melakukan kueri padaHostId
, misalnya untuk menemukan game yang di-hosting oleh pengguna tertentu. -
OpponentId- StatusDate -indeks. Indeks ini memiliki
OpponentId
sebagai kunci partisi danStatusDate
sebagai kunci urutan. Anda dapat menggunakan indeks ini untuk melakukan kueri padaOpponent
, misalnya untuk menemukan game yang lawannya adalah pengguna tertentu.
Indeks ini disebut indeks sekunder global karena kunci partisi dalam indeks ini tidak sama dengan kunci partisi (
GameId
), yang digunakan dalam kunci primer tabel.Perhatikan bahwa kedua indeks menentukan
StatusDate
sebagai kunci urutan. Ini akan memungkinkan hal berikut:-
Anda dapat mengkueri menggunakan operator perbandingan
BEGINS_WITH
. Misalnya, Anda dapat menemukan semua game dengan atributIN_PROGRESS
yang di-hosting oleh pengguna tertentu. Dalam hal ini, operatorBEGINS_WITH
memeriksa nilaiStatusDate
yang dimulai denganIN_PROGRESS
. -
DynamoDB menyimpan item dalam indeks dalam urutan yang diurutkan, berdasarkan nilai kunci urutan. Jadi jika semua awalan status sama (misalnya,
IN_PROGRESS
), ISO format yang digunakan untuk bagian tanggal akan memiliki item yang diurutkan dari yang paling lama ke yang terbaru. Pendekatan ini memungkinkan kueri tertentu untuk dilakukan secara efisien, misalnya berikut ini:-
Ambil hingga 10 game
IN_PROGRESS
terbaru yang di-hosting oleh pengguna yang masuk. Untuk kueri ini, Anda menentukan indeksHostId-StatusDate-index
. -
Ambil hingga 10 game
IN_PROGRESS
terbaru yang lawannya adalah pengguna yang masuk. Untuk kueri ini, Anda menentukan indeksOpponentId-StatusDate-index
.
-
-
Untuk informasi selengkapnya tentang indeks sekunder, lihat Meningkatkan akses data dengan indeks sekunder di DynamoDB.
2.2: Aplikasi dalam tindakan (kode panduan)
Aplikasi ini memiliki dua halaman utama:
-
Halaman rumah — Halaman ini memberi pengguna login sederhana, CREATEtombol untuk membuat tic-tac-toe game baru, daftar game yang sedang berlangsung, riwayat game, dan undangan game aktif yang tertunda.
Halaman beranda tidak disegarkan secara otomatis; Anda harus menyegarkan halaman untuk menyegarkan daftar.
-
Halaman permainan — Halaman ini menunjukkan tic-tac-toe kisi tempat pengguna bermain.
Aplikasi memperbarui halaman game secara otomatis setiap detik. JavaScript Di browser Anda memanggil server web Python setiap detik untuk menanyakan tabel Game apakah item game dalam tabel telah berubah. Jika ada, JavaScript memicu penyegaran halaman sehingga pengguna melihat papan yang diperbarui.
Mari kita lihat secara detail cara kerja aplikasi.
Halaman beranda
Setelah pengguna masuk, aplikasi menampilkan tiga daftar informasi berikut.

-
Undangan – Daftar ini menampilkan hingga 10 undangan terbaru dari pengguna lain yang menunggu penerimaan oleh pengguna yang masuk. Dalam tangkapan layar sebelumnya, user1 memiliki undangan tertunda dari user5 dan user2.
-
Game sedang dimainkan – Daftar ini menampilkan hingga 10 game terbaru yang sedang dimainkan. Ini adalah game yang dimainkan pengguna secara aktif, yang berstatus
IN_PROGRESS
. Dalam tangkapan layar, user1 secara aktif memainkan tic-tac-toe game dengan user3 dan user4. -
Riwayat terbaru – Daftar ini menampilkan hingga 10 game terbaru yang telah diselesaikan pengguna, yang berstatus
FINISHED
. Dalam game yang ditampilkan di tangkapan layar, user1 sebelumnya pernah bermain dengan user2. Untuk setiap game yang telah selesai dimainkan, daftar ini menunjukkan hasil game.
Dalam kode, fungsi index
(di application.py
) membuat tiga panggilan berikut untuk mengambil informasi status game:
inviteGames = controller.getGameInvites(session["username"])
inProgressGames = controller.getGamesWithStatus(session["username"], "IN_PROGRESS")
finishedGames = controller.getGamesWithStatus(session["username"], "FINISHED")
Setiap panggilan ini mengembalikan daftar item dari DynamoDB yang dikemas oleh objek Game
. Sangat mudah untuk mengekstrak data dari objek-objek ini dalam tampilan. Fungsi indeks meneruskan daftar objek ini ke tampilan untuk merenderHTML.
return render_template("index.html",
user=session["username"],
invites=inviteGames,
inprogress=inProgressGames,
finished=finishedGames)
Tic-Tac-ToeAplikasi mendefinisikan Game
kelas terutama untuk menyimpan data game diambil dari DynamoDB. Fungsi tersebut mengembalikan daftar objek Game
yang memungkinkan Anda mengisolasi aplikasi lainnya dari kode yang terkait dengan item Amazon DynamoDB. Dengan demikian, fungsi tersebut membantu Anda memisahkan kode aplikasi Anda dari detail lapisan penyimpanan data.
Pola arsitektur yang dijelaskan di sini juga disebut sebagai pola model-view-controller (MVC) UI. Dalam hal ini, instance Game
objek (mewakili data) adalah model, dan HTML halaman adalah tampilan. Pengontrol dibagi menjadi dua file. File application.py
memiliki logika pengontrol untuk kerangka kerja Flask, dan logika bisnis diisolasi dalam file gameController.py
. Artinya, aplikasi menyimpan semua yang ada hubungannya dengan SDK DynamoDB dalam file terpisahnya sendiri di folder. dynamodb
Mari kita meninjau tiga fungsi dan cara fungsi tersebut mengkueri tabel Game menggunakan indeks sekunder global untuk mengambil data yang relevan.
Menggunakan getGameInvites untuk mendapatkan daftar undangan game yang tertunda
Fungsi getGameInvites
mengambil daftar 10 undangan tertunda terbaru. Game ini telah dibuat oleh pengguna, tetapi lawan belum menerima undangan game. Untuk game tersebut, statusnya tetap PENDING
sampai lawan menerima undangan. Jika lawan menolak undangan, aplikasi akan menghapus item yang sesuai dari tabel.
Fungsi menentukan kueri sebagai berikut:
-
Fungsi menentukan indeks
OpponentId-StatusDate-index
untuk digunakan dengan nilai kunci indeks berikut dan operator perbandingan:-
Kunci partisinya adalah
OpponentId
dan mengambil kunci indeks
.user ID
-
Kunci urutannya adalah
StatusDate
dan mengambil operator perbandingan serta nilai kunci indeksbeginswith="PENDING_"
.
Anda menggunakan indeks
OpponentId-StatusDate-index
untuk mengambil game yang mengundang pengguna yang masuk—yaitu, pengguna yang masuk adalah lawannya. -
-
Kueri membatasi hasil hingga 10 item.
gameInvitesIndex = self.cm.getGamesTable().query(
Opponent__eq=user,
StatusDate__beginswith="PENDING_",
index="OpponentId-StatusDate-index",
limit=10)
Dalam indeks, untuk setiap OpponentId
(kunci partisi) DynamoDB menyimpan item yang diurutkan berdasarkan StatusDate
(kunci urutan). Oleh karena itu, game yang dikembalikan oleh kueri akan berupa 10 game terbaru.
Menggunakan getGamesWith Status untuk mendapatkan daftar game dengan status tertentu
Setelah lawan menerima undangan game, status game berubah menjadi IN_PROGRESS
. Setelah game selesai, status berubah menjadi FINISHED
.
Kueri untuk menemukan game yang sedang dimainkan atau telah selesai sama, kecuali nilai statusnya berbeda. Oleh karena itu, aplikasi mendefinisikan fungsi getGamesWithStatus
, yang mengambil nilai status sebagai parameter.
inProgressGames = controller.getGamesWithStatus(session["username"], "IN_PROGRESS")
finishedGames = controller.getGamesWithStatus(session["username"], "FINISHED")
Bagian berikut membahas game yang sedang berlangsung, tetapi deskripsi yang sama juga berlaku untuk game yang sudah selesai.
Daftar game yang sedang berlangsung untuk pengguna tertentu meliputi hal berikut ini:
-
Game yang sedang berlangsung yang di-hosting oleh pengguna
-
Game yang sedang berlangsung yang lawannya adalah pengguna
Fungsi getGamesWithStatus
menjalankan dua kueri berikut, setiap kali menggunakan indeks sekunder yang sesuai.
-
Fungsi mengkueri tabel
Games
menggunakan indeksHostId-StatusDate-index
. Untuk indeks, kueri menentukan nilai kunci primer—baik nilai kunci partisi (HostId
) dan kunci urutan (StatusDate
), bersama dengan operator perbandingan.hostGamesInProgress = self.cm.getGamesTable ().query(HostId__eq=user, StatusDate__beginswith=status, index="HostId-StatusDate-index", limit=10)
Perhatikan sintaks Python untuk operator perbandingan:
-
HostId__eq=user
menentukan operator perbandingan kesetaraan. -
StatusDate__beginswith=status
menentukan operator perbandinganBEGINS_WITH
.
-
-
Fungsi mengkueri tabel
Games
menggunakan indeksOpponentId-StatusDate-index
.oppGamesInProgress = self.cm.getGamesTable().query(Opponent__eq=user, StatusDate__beginswith=status, index="OpponentId-StatusDate-index", limit=10)
-
Fungsi tersebut kemudian menggabungkan dua daftar, mengurutkan, dan membuat daftar objek
Game
untuk 0 hingga 10 item pertama, serta mengembalikan daftar tersebut ke fungsi pemanggilan (yaitu, indeks).games = self.mergeQueries(hostGamesInProgress, oppGamesInProgress) return games
Halaman game
Halaman game adalah tempat pengguna memainkan tic-tac-toe game. Halaman game menampilkan grid game bersama dengan informasi yang relevan terkait game. Tangkapan layar berikut menunjukkan contoh game yang sedang dimainkan:

Aplikasi menampilkan halaman game dalam situasi-situasi berikut:
-
Pengguna membuat game yang mengundang pengguna lain untuk ikut bermain.
Dalam hal ini, halaman menunjukkan pengguna sebagai host dan status game sebagai
PENDING
, menunggu lawan menerima undangan. -
Pengguna menerima salah satu undangan yang tertunda di halaman beranda.
Dalam hal ini, halaman menunjukkan pengguna sebagai lawan dan status game sebagai
IN_PROGRESS
.
Pemilihan pengguna di papan menghasilkan permintaan POST
formulir untuk aplikasi. Artinya, Flask memanggil selectSquare
fungsi (inapplication.py
) dengan data HTML formulir. Fungsi ini, pada gilirannya, memanggil fungsi updateBoardAndTurn
(di gameController.py
) untuk memperbarui item game sebagai berikut:
-
Fungsi menambahkan atribut baru khusus untuk langkah.
-
Fungsi memperbarui nilai atribut
Turn
untuk pengguna yang mendapat giliran berikutnya.
controller.updateBoardAndTurn(item, value, session["username"])
Fungsi mengembalikan true jika pembaruan item berhasil; jika tidak, fungsi akan mengembalikan false. Perhatikan hal berikut terkait fungsi updateBoardAndTurn
:
-
Fungsi ini memanggil
update_item
fungsi SDK untuk Python untuk membuat serangkaian pembaruan terbatas ke item yang ada. Fungsi ini dipetakan ke operasiUpdateItem
di DynamoDB. Untuk informasi selengkapnya, lihat UpdateItem.catatan
Perbedaan antara operasi
UpdateItem
danPutItem
adalah bahwaPutItem
menggantikan seluruh item. Untuk informasi selengkapnya, lihat PutItem.
Untuk panggilan update_item
, kode mengidentifikasi berikut ini:
-
Kunci primer tabel
Games
(yaitu,ItemId
).key = { "GameId" : { "S" : gameId } }
-
Atribut baru yang akan ditambahkan, khusus untuk langkah pengguna saat ini, dan nilainya (misalnya,
TopLeft="X"
).attributeUpdates = { position : { "Action" : "PUT", "Value" : { "S" : representation } } }
-
Kondisi yang harus true agar pembaruan dapat diterapkan:
-
Game harus sedang dimainkan. Yaitu, nilai atribut
StatusDate
harus diawali denganIN_PROGRESS
. -
Giliran saat ini harus merupakan giliran pengguna yang valid sebagaimana ditentukan oleh atribut
Turn
. -
Kotak yang dipilih pengguna harus tersedia. Artinya, atribut yang sesuai dengan kotak tidak boleh ada.
expectations = {"StatusDate" : {"AttributeValueList": [{"S" : "IN_PROGRESS_"}], "ComparisonOperator": "BEGINS_WITH"}, "Turn" : {"Value" : {"S" : current_player}}, position : {"Exists" : False}}
-
Sekarang fungsi memanggil update_item
untuk memperbarui item.
self.cm.db.update_item("Games", key=key,
attribute_updates=attributeUpdates,
expected=expectations)
Setelah fungsi kembali, fungsi selectSquare
memanggil pengalihan, seperti yang ditunjukkan dalam contoh berikut.
redirect("/game="+gameId)
Panggilan ini menyebabkan browser disegarkan. Sebagai bagian dari penyegaran ini, aplikasi memeriksa apakah game berakhir dengan kemenangan atau seri. Jika game sudah selesai, aplikasi akan memperbarui item game.