Sejauh ini, kami puas dengan pola akses seputar kreasi dan pengambilan entitas inti dalam aplikasi seluler kami, seperti Pengguna dan Foto. Kami juga telah belajar cara menggunakan indeks inversi untuk mengaktifkan pola kueri tambahan pada entitas kami.

Di modul ini, kami akan memenuhi dua pola akses:

  • Bereaksi terhadap foto (Tulis)
  • Mengikuti teman (Tulis)

Perhatikan bahwa kedua pola akses ini menulis data ke DynamoDB, berbeda dengan pola baca yang besar yang telah kami lakukan sejauh ini.

Untuk memenuhi kedua pola akses pada langkah-langkah di bawah ini, kami akan menggunakan transaksi DynamoDB ACID. Transaksi DynamoDB dirilis pada November 2018. Mari kita dapatkan primer cepat tentang bagaimana cara kerja transaksi di DynamoDB.

Transaksi dalam sistem relasional populer untuk operasi yang memengaruhi beberapa elemen data sekaligus. Misalnya, bayangkan Anda menjalankan bank. Satu pelanggan, Karen, mentransfer 100 USD ke pelanggan lain, Sujith. Saat mencatat transaksi ini, Anda akan menggunakan transaksi untuk memastikan perubahan diterapkan pada saldo kedua pelanggan, bukan hanya salah satunya.

Tambahan transaksi DynamoDB memudahkan pembuatan aplikasi yang Anda butuhkan untuk mengubah beberapa item sebagai bagian dari satu operasi. Dengan transaksi DynamoDB, Anda dapat mengoperasikan hingga 10 item sebagai bagian dari sebuah permintaan transaksi.

Dalam panggilan API TransactWriteItem, Anda dapat menggunakan jenis operasi berikut:

  • Letakkan: Untuk memasukkan atau menimpa item;
  • Perbarui: Untuk memperbarui item yang sudah ada;
  • Hapus: Untuk menghapus item;
  • ConditionCheck: Untuk menyatakan suatu kondisi pada item yang ada tanpa mengubah item.

Pada langkah-langkah di bawah ini, kami akan menggunakan transaksi DynamoDB dalam dua cara untuk menangani operasi yang kompleks.

Waktu untuk Menyelesaikan Modul: 20 Menit


  • Langkah 1: Bereaksi terhadap foto

    Pola akses pertama yang kita bahas dalam modul ini adalah bereaksi terhadap foto.

    Ketika menambahkan reaksi pengguna terhadap foto, kita perlu melakukan beberapa hal.

    • Pastikan bahwa pengguna belum menggunakan jenis reaksi ini di foto ini.
    • Buat entitas Reaksi baru untuk menyimpan reaksi.
    • Tambahkan jenis reaksi yang tepat di properti reaksi pada entitas Foto sehingga kita dapat menampilkan detail reaksi pada foto.

    Perhatikan bahwa hal ini memerlukan tindakan tulis di dua item yang berbeda -- entitas Foto yang ada dan entitas Reaksi baru -- serta logika kondisional untuk salah satu item. Ini adalah jenis operasi yang sangat cocok untuk transaksi DynamoDB.

    Dalam kode yang Anda unduh, terdapat skrip dalam direktori aplikasi/ yang disebut add_reaction.py yang mencakup fungsi untuk menambahkan reaksi terhadap foto. Fungsi dalam file tersebut menggunakan transaksi DynamoDB untuk menambahkan reaksi.

    Konten file tersebut adalah sebagai berikut:

    import datetime
    
    import boto3
    
    dynamodb = boto3.client('dynamodb')
    
    REACTING_USER = 'kennedyheather'
    REACTION_TYPE = 'sunglasses'
    PHOTO_USER = 'ppierce'
    PHOTO_TIMESTAMP = '2019-04-14T08:09:34'
    
    
    def add_reaction_to_photo(reacting_user, reaction_type, photo_user, photo_timestamp):
        reaction = "REACTION#{}#{}".format(reacting_user, reaction_type)
        photo = "PHOTO#{}#{}".format(photo_user, photo_timestamp)
        user = "USER#{}".format(photo_user)
        try:
            resp = dynamodb.transact_write_items(
                TransactItems=[
                    {
                        "Put": {
                            "TableName": "quick-photos",
                            "Item": {
                                "PK": {"S": reaction},
                                "SK": {"S": photo},
                                "reactingUser": {"S": reacting_user},
                                "reactionType": {"S": reaction_type},
                                "photo": {"S": photo},
                                "timestamp": {"S": datetime.datetime.now().isoformat() }
                            },
                            "ConditionExpression": "attribute_not_exists(SK)",
                            "ReturnValuesOnConditionCheckFailure": "ALL_OLD"
                        },
                    },
                    {
                        "Update": {
                            "TableName": "quick-photos",
                            "Key": {"PK": {"S": user}, "SK": {"S": photo}},
                            "UpdateExpression": "SET reactions.#t = reactions.#t + :i",
                            "ExpressionAttributeNames": {
                                "#t": reaction_type
                            },
                            "ExpressionAttributeValues": {
                                ":i": { "N": "1" },
                            },
                            "ReturnValuesOnConditionCheckFailure": "ALL_OLD"
                        }
                    }
                ]
            )
            print("Added {} reaction from {}".format(reaction_type, reacting_user))
            return True
        except Exception as e:
            print("Could not add reaction to photo")
    
    add_reaction_to_photo(REACTING_USER, REACTION_TYPE, PHOTO_USER, PHOTO_TIMESTAMP)
    

    Di fungsi add_reaction_to_photo , kita menggunakan metode transact_write_items() untuk melaksanakan transaksi tulis. Transaksi kita memiliki dua operasi.

    Pertama, kita melakukan operasi Meletakkan untuk menyisipkan entitas Reaksi baru. Sebagai bagian dari operasi tersebut, kita menentukan kondisi bahwa atribut SK tidak boleh ada untuk item ini. Ini adalah cara untuk memastikan bahwa item dengan PK dan SK ini tidak ada. Jika berhasil, itu berarti pengguna telah menambahkan reaksi ini terhadap foto ini.

    Operasi kedua adalah operasi Perbarui pada entitas Pengguna untuk menambah jenis reaksi di peta atribut reaksi. Perbarui ekspresi DynamoDB yang luar biasa memungkinkan Anda melakukan penambahan atomik tanpa perlu mengambil item terlebih dulu dan lalu memperbaruinya.

    Jalankan skrip ini dengan perintah berikut di terminal Anda.

    python application/add_reaction.py

    Output di terminal Anda harus menunjukkan bahwa pengguna telah ditambahkan ke foto.

    Added sunglasses reaction from kennedyheather

    Perhatikan bahwa jika Anda mencoba menjalankan skrip lagi, fungsinya akan gagal. Pengguna kennedyheather telah menambahkan reaksi ini ke foto ini, sehingga mencoba melakukannya lagi akan melanggar ekspresi kondisi dalam operasi untuk membuat entitas Reaksi. Dengan kata lain, fungsi idempoten dan pemanggilan berulang dengan input yang sama tidak akan memiliki konsekuensi yang tidak diinginkan.

    Penambahan transaksi DynamoDB sangat menyederhanakan alur kerja di sekitar operasi kompleks seperti ini. Sebelumnya, proses ini membutuhkan beberapa panggilan API dengan kondisi kompleks dan pemulihan manual jika terjadi konflik. Sekarang ini dapat diimplementasikan dengan kurang dari 50 baris kode.

    Di langkah berikutnya, kita akan melihat bagaimana menangani pola akses “Ikuti pengguna” kita.

  • Langkah 2: Mengikuti pengguna

    Di aplikasi Anda, satu pengguna dapat mengikuti pengguna lainnya. Ketika aplikasi backend mendapat permintaan untuk mengikuti pengguna, kita perlu melakukan empat hal:

    • Periksa apakah pengguna berikut belum mengikuti pengguna yang diminta;
    • Buat entitas Pertemanan untuk merekam hubungan berikut;
    • Tambahkan jumlah pengikut untuk pengguna yang diikuti;
    • Tambahkan jumlah yang mengikuti untuk pengguna yang mengikuti;

    Di kode yang Anda unduh, terdapat file di direktori application/ yang disebut follow_user.py. Konten file tersebut adalah sebagai berikut:

    import datetime
    
    import boto3
    
    dynamodb = boto3.client('dynamodb')
    
    FOLLOWED_USER = 'tmartinez'
    FOLLOWING_USER = 'john42'
    
    
    def follow_user(followed_user, following_user):
        user = "USER#{}".format(followed_user)
        friend = "#FRIEND#{}".format(following_user)
        user_metadata = "#METADATA#{}".format(followed_user)
        friend_user = "USER#{}".format(following_user)
        friend_metadata = "#METADATA#{}".format(following_user)
        try:
            resp = dynamodb.transact_write_items(
                TransactItems=[
                    {
                        "Put": {
                            "TableName": "quick-photos",
                            "Item": {
                                "PK": {"S": user},
                                "SK": {"S": friend},
                                "followedUser": {"S": followed_user},
                                "followingUser": {"S": following_user},
                                "timestamp": {"S": datetime.datetime.now().isoformat()},
                            },
                            "ConditionExpression": "attribute_not_exists(SK)",
                            "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
                        }
                    },
                    {
                        "Update": {
                            "TableName": "quick-photos",
                            "Key": {"PK": {"S": user}, "SK": {"S": user_metadata}},
                            "UpdateExpression": "SET followers = followers + :i",
                            "ExpressionAttributeValues": {":i": {"N": "1"}},
                            "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
                        }
                    },
                    {
                        "Update": {
                            "TableName": "quick-photos",
                            "Key": {"PK": {"S": friend_user}, "SK": {"S": friend_metadata}},
                            "UpdateExpression": "SET following = following + :i",
                            "ExpressionAttributeValues": {":i": {"N": "1"}},
                            "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
                        }
                    },
                ]
            )
            print("User {} is now following user {}".format(following_user, followed_user))
            return True
        except Exception as e:
            print(e)
            print("Could not add follow relationship")
    
    follow_user(FOLLOWED_USER, FOLLOWING_USER)

    Fungsi follow_user di file ini serupa dengan fungsi yang Anda miliki di aplikasi Anda. Dibutuhkan dua nama pengguna -- salah satu pengguna yang diikuti dan satu dari pengguna berikut -- dan menjalankan permintaan untuk membuat entitas Pertemanan dan memperbarui dua entitas Pengguna.

    Jalankan skrip di terminal Anda dengan perintah berikut.

    python application/follow_user.py

    Anda dapat melihat output di terminal Anda yang menunjukkan bahwa operasi berhasil.

    User john42 is now following user tmartinez

    Coba jalankan skrip untuk kedua kalinya di terminal Anda. Kali ini, Anda akan mendapatkan pesan kesalahan yang menunjukkan bahwa Anda tidak dapat menambahkan hubungan mengikuti. Ini karena pengguna ini sekarang mengikuti pengguna yang diminta, jadi permintaan kita kemudian gagal dengan pemeriksaan bersyarat pada item tersebut.

  • Penutup

    Di modul ini, kita melihat cara memenuhi operasi penulisan lanjutan dalam aplikasi kita. Pertama, kita menggunakan transaksi DynamoDB untuk membuat pengguna bereaksi terhadap foto. Dengan transaksi, kita menangani penulisan kondisional yang kompleks di beberapa entitas dalam satu permintaan. Lebih lanjut, kita melihat cara menggunakan ekspresi pembaruan DynamoDB untuk meningkatkan atribut bersarang di properti peta.

    Kedua, kita mengimplementasikan fungsi kepada pengguna untuk mengikuti pengguna lainnya. Ini diperlukan untuk mengubah tiga item dalam satu permintaan, sekaligus melakukan pemeriksaan bersyarat pada salah satu item. Walaupun ini biasanya operasi yang sulit, DynamoDB memudahkan penanganannya dengan transaksi DynamoDB.

    Dalam modul berikutnya, kita akan membersihkan sumber daya yang kita buat dan melihat beberapa langkah selanjutnya di jalur pembelajaran DynamoDB.