จนถึงตอนนี้เราได้ทำตามรูปแบบการเข้าถึงทั่วทั้งการสร้างและการเรียกข้อมูลของเอนทิตีหลักในแอปพลิเคชันบนมือถือของเรา เช่น ผู้ใช้ และ รูปภาพ ทั้งนี้เรายังได้เรียนรู้วิธีใช้ดัชนีแบบอินเวิร์ทเพื่อเปิดใช้งานรูปแบบการสืบค้นเพิ่มเติมบนเอนทิตีของเรา

ในโมดูลนี้ เราจะทำตามรูปแบบการเข้าถึง 2 แบบ:

  • ตอบสนองต่อรูปภาพ (เขียน)
  • ติดตามเพื่อน (เขียน)

โปรดทราบว่ารูปแบบการเข้าถึงทั้งสองแบบนั้นคือการเขียนข้อมูลไปยัง DynamoDB ซึ่งแตกต่างกับรูปแบบที่ต้องอ่านจำนวนมากซึ่งเราเคยทำอย่างที่ผ่านๆ มา

เพื่อให้เป็นไปตามรูปแบบการเข้าถึงทั้งสองแบบตามขั้นตอนด้านล่าง เราจะใช้ธุรกรรม DynamoDB ACID ธุรกรรม DynamoDB ได้เปิดตัวเมื่อเดือนพฤศจิกายน 2018 มาดูคำอธิบายแบบคร่าวๆ ในงาน DynamoDB

ธุรกรรมนั้นเป็นที่นิยมในระบบเชิงสัมพันธ์สำหรับการทำงานซึ่งมีผลต่อองค์ประกอบข้อมูลเป็นจำนวนมากในครั้งเดียว ตัวอย่างเช่น ลองจินตนาการว่าคุณกำลังทำงานธนาคาร ลูกค้ารายหนึ่งชื่อ Karen โอนเงิน 100 USD ไปให้ลูกค้าอีกรายชื่อ Sujith เมื่อบันทึกธุรกรรมนี้ คุณจะใช้ธุรกรรมเพื่อให้แน่ใจว่ามีการเปลี่ยนแปลงในยอดเงินคงเหลือของลูกค้าทั้งสองคน ไม่ใช่เพียงหนึ่งคน

การใช้ธุรกรรม DynamoDB เข้ามาช่วยเสริมทำให้ง่ายต่อการสร้างแอปพลิเคชันซึ่งเปลี่ยนรายการที่หลากหลายให้เป็นส่วนหนึ่งของการดำเนินการเดียว ด้วยธุรกรรม DynamoDB คุณสามารถดำเนินการได้ถึง 10 รายการให้เป็นส่วนหนึ่งของคำขอการทำธุรกรรมครั้งเดียว

ในการเรียกใช้ API TransactWriteItem คุณสามารถใช้ประเภทของการดำเนินการต่อไปนี้ได้

  • ใส่: สำหรับการแทรกหรือเขียนทับรายการ;
  • อัปเดต: สำหรับการอัปเดตรายการที่มีอยู่;
  • ลบ: สำหรับการลบรายการ;
  • ตรวจสอบสภาวะ: สำหรับการประเมินสภาวะของรายการที่มีอยู่โดยไม่มีการเปลี่ยนแปลงรายการ

ในขั้นตอนด้านล่าง เราจะใช้ธุรกรรม DynamoDB ในสองวิธีเพื่อจัดการกับการทำงานที่มีความซับซ้อน

ระยะเวลาที่ใช้ในการศึกษาโมดูล: 20 นาที


  • ขั้นตอนที่ 1: ตอบสนองต่อรูปภาพ

    รูปแบบการเข้าถึงแรกที่เรากล่าวถึงในโมดูลนี้คือการตอบสนองต่อรูปภาพ

    เมื่อเพิ่มการตอบสนองต่อรูปภาพของผู้ใช้ เราจำเป็นต้องดำเนินการหลายอย่างดังนี้:

    • ยืนยันว่าผู้ใช้ยังไม่เคยใช้ประเภทของการตอบสนองนี้บนรูปภาพ
    • สร้างเอนทิตี การตอบสนอง ใหม่เพื่อจัดเก็บการตอบสนอง
    • เพิ่มประเภทของการตอบสนองที่เหมาะสมในคุณสมบัติของ การตอบสนอง บนเอนทิตี รูปภาพ เพื่อที่เราจะสามารถแสดงรายละเอียดของการตอบสนองบนรูปภาพได้

    โปรดทราบว่าการดำเนินการเช่นนี้จำเป็นต้องมีการดำเนินการเขียนในทั้งสองรายการที่แตกต่างกัน -- เอนทิตี รูปภาพ ที่มีอยู่แล้วและเอนทิตีการตอบสนองแบบใหม่ -- รวมถึงตรรกะตามเงื่อนไขสำหรับแต่ละรายการ ซึ่งนี่คือประเภทของการดำเนินการที่เหมาะสมเป็นอย่างดีสำหรับธุรกรรม DynamoDB

    ในโค้ดที่คุณดาวน์โหลดนั้น จะมีสคริปต์ในไดเรกทอรี application/ ที่เรียกว่า add_reaction.py ซึ่งจะมีฟังก์ชันสำหรับการเพิ่มการตอบสนองไปยังรูปภาพ ฟังก์ชันในไฟล์นั้นใช้ธุรกรรม DynamoDB เพื่อเพิ่มการตอบสนอง

    เนื้อหาในไฟล์มีดังต่อไปนี้:

    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)
    

    ในฟังก์ชัน add_reaction_to_photo เราได้ใช้วิธีการ transact_write_items() เพื่อดำเนินธุรกรรมการเขียน ธุรกรรมของเรามี 2 การทำงาน

    การทำงานแรก เราจะใช้การ ใส่ เพื่อแทรกเอนทิตี การตอบสนอง ใหม่ ในส่วนหนึ่งของการทำงานนั้น เราจะกำหนดสภาวะซึ่งควรจะไม่มีแอตทริบิวต์ SK อยู่สำหรับรายการนี้ นี่คือวิธีให้มั่นใจว่าไม่มีรายการที่มี PK และ SK อยู่ก่อนแล้ว หากมี นั่นหมายความว่าผู้ใช้ได้เพิ่มการตอบสนองนี้ในรูปภาพแล้ว

    การทำงานที่ 2 คือการ อัปเดต เอนทิตีของ ผู้ใช้ เพื่อเพิ่มประเภทของการตอบสนองในแมปแอตทริบิวต์ของ การตอบสนอง การแสดงอัปเดต อันทรงพลังของ DynamoDB ช่วยให้คุณดำเนินการเพิ่มแบบอะตอมโดยไม่จำเป็นต้องเรียกดูรายการก่อนแล้วจึงอัปเดต

    เรียกใช้สคริปต์นี้ด้วยคำสั่งต่อไปนี้ในเทอร์มินัลของคุณ

    python application/add_reaction.py

    ผลลัพธ์ที่ได้บนเทอร์มินัลควรแสดงว่าการตอบสนองถูกเพิ่มไปยังรูปภาพแล้ว

    Added sunglasses reaction from kennedyheather

    โปรดทราบว่าถ้าคุณพยายามเรียกใช้สคริปต์อีกครั้ง ฟังก์ชันจะล้มเหลว ผู้ใช้ kennedyheather ได้เพิ่มการตอบสนองนี้ไปยังรูปภาพแล้ว ดังนั้นการดำเนินการซ้ำอีกครั้งจะเป็นการละเมิดการแสดงเงื่อนไขในการสร้างเอนทิตี การตอบสนอง หรืออีกนัยหนึ่ง ฟังก์ชันจะเป็นค่าเดิมเสมอและการเรียกใช้ซ้ำด้วยข้อมูลป้อนเดียวกันจะไม่มีผลกระทบที่ไม่คาดคิด

    การเพิ่มธุรกรรม DynamoDB ช่วยลดความซับซ้อนของเวิร์กโฟลว์ในการทำงานที่มีความซับซ้อนเช่นนี้ได้มาก ก่อนหน้านี้ การทำเช่นนี้จำเป็นต้องมีการเรียกใช้ API ที่มีเงื่อนไขซับซ้อนหลายรายการและการย้อนกลับการทำงานด้วยตนเองในกรณีที่เกิดข้อขัดแย้งกันขึ้น ตอนนี้สามารถใช้งานได้ด้วยโค้ดไม่เกิน 50 บรรทัด

    ในขั้นตอนต่อไป เราจะได้เห็นวิธีจัดการกับรูปแบบการเข้าถึง “การติดตามผู้ใช้” ของเรา

  • ขั้นตอนที่ 2: การติดตามผู้ใช้

    ในแอปพลิเคชันของคุณนั้น ผู้ใช้รายหนึ่งสามารถติดตามผู้ใช้อีกรายได้ เมื่อแบ็คเอนด์ของแอปพลิเคชันได้รับคำขอติดตามผู้ใช้ เราจำเป็นต้องดำเนินการสี่ขั้นตอนต่อไปนี้:

    • ตรวจสอบว่าผู้ใช้ที่ต้องการติดตามไม่ได้ติดตามผู้ใช้ที่ถูกร้องขอการติดตามอยู่แล้ว;
    • สร้างเอนทิตี ความสัมพันธ์ เพื่อบันทึกความสัมพันธ์ของการติดตาม;
    • เพิ่มการนับจำนวนผู้ติดตามสำหรับผู้ใช้ที่ถูกติดตาม;
    • เพิ่มการนับจำนวนการติดตามสำหรับการติดตามของผู้ใช้

    ในโค้ดที่คุณดาวน์โหลด จะมีไฟล์ในไดเรกทอรี application/ ที่เรียกว่า follow_user.py เนื้อหาในไฟล์มีดังต่อไปนี้:

    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)

    ฟังก์ชัน follow_user มีความคล้ายคลึงกับฟังก์ชันที่มีในแอปพลิเคชันของคุณ โดยต้องใช้ชื่อผู้ใช้สองรายการ -- รายการแรกคือชื่อผู้ใช้ที่ถูกติดตามและอีกรายการคือชื่อผู้ใช้ที่ติดตาม -- แล้วเรียกใช้คำขอสร้างเอนทิตี มิตรภาพ และอัปเดตเอนทิตี ผู้ใช้ ทั้งสองเอนทิตี

    เรียกใช้สคริปต์ในเทอร์มินัลด้วยคำสั่งต่อไปนี้

    python application/follow_user.py

    ควรจะเห็นผลลัพธ์ในเทอร์มินัลซึ่งแสดงให้เห็นว่าการดำเนินการสำเร็จแล้ว

    User john42 is now following user tmartinez

    ทดลองเรียกใช้สคริปต์อีกครั้งบนเทอร์มินัล ครั้งนี้คุณจะเห็นข้อความแสดงข้อผิดพลาดที่ระบุว่าคุณไม่สามารถเพิ่มความสัมพันธ์ของการติดตามได้ ซึ่งเป็นเพราะผู้ใช้นี้ได้ติดตามผู้ใช้ที่ร้องขออยู่แล้วในขณะนี้ ดังนั้นคำขอของเราจึงไม่ผ่านการตรวจสอบเงื่อนไขของรายการ

  • สรุป

    ในโมดูลนี้ เรายังได้เห็นวิธีทำให้การเขียนขั้นสูง 2 รูปแบบเป็นไปตามแอปพลิเคชันของเรา ขั้นแรก เราได้ใช้ธุรกรรม DynamoDB เพื่อให้ผู้ใช้ตอบสนองต่อรูปภาพ ด้วยธุรกรรม เราได้จัดการกับการเขียนตามเงื่อนไขที่ซับซ้อนกับรายการหลายรายการในคำขอเดียว นอกจากนี้ เรายังได้เห็นวิธีใช้การแสดงการอัปเดตของ DynamoDB เพื่อเพิ่มแอตทริบิวต์แบบทับซ้อนในคุณสมบัติแมป

    ขั้นที่สอง เราได้ใช้ฟังก์ชันที่ให้ผู้ใช้ได้ติดตามผู้ใช้อื่น ซึ่งขั้นตอนนี้จำเป็นต้องเปลี่ยนแปลงรายการสามรายการในคำขอเดียว ซึ่งในขณะเดียวกันต้องทำการตรวจสอบเงื่อนไขของแต่ละรายการด้วย โดยปกติแล้วการดำเนินการเช่นนี้จะมีความยากลำบากอยู่ในตัว แต่ DynamoDB สามารถทำให้การจัดการเรื่องนี้ง่ายขึ้นได้ด้วยธุรกรรม DynamoDB

    ในโมดูลถัดไป เราจะได้ล้างข้อมูลทรัพยากรที่เราสร้างและดูขั้นตอนถัดไปในเส้นทางการเรียนรู้ของ DynamoDB