ทำความเข้าใจกับระบบการแจ้งเตือน


15

ฉันค้นหาวิธีการสร้างระบบการแจ้งเตือนใน SE และที่อื่น ๆ และพบว่าตัวเองถูกดึงไปยังโซลูชันที่เป็นคำตอบที่ยอมรับได้ที่นี่: /programming/9735578/building-a-notification-system ซึ่งใช้ โครงสร้างนี้:

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
notification       notification_object      notification_change 
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
ID           ║—1:n—→║ID                 ║—1:n—→║ID                  
userID             notificationID           notificationObjectID
╚═════════════╝      object                   verb                
                     ╚═══════════════════╝      actor               
                                                ╚════════════════════╝

การแจ้งเตือนเกี่ยวกับบางสิ่งบางอย่าง (object = event, มิตรภาพ .. ) กำลังถูกเปลี่ยนแปลง (กริยา = เพิ่ม, ขอ .. ) โดยบางคน (นักแสดง) และรายงานต่อผู้ใช้ (เรื่อง) นี่คือโครงสร้างข้อมูลปกติ (แม้ว่าฉันจะใช้ MongoDB) คุณต้องแจ้งผู้ใช้บางคนถึงการเปลี่ยนแปลง ดังนั้นจึงเป็นการแจ้งเตือนแบบต่อผู้ใช้ .. หมายความว่าหากมีผู้ใช้ 100 คนที่เกี่ยวข้องคุณสร้างการแจ้งเตือน 100 รายการ

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

ฉันไม่แน่ใจว่านี่เป็นแบบจำลองที่ฉันจะตามมา แต่ได้รับจำนวน upvotes ที่มีฉันแน่ใจว่ามันจะเป็นประโยชน์ต่อฉันที่จะเข้าใจมันและแน่นอนฉันต้องการเรียนรู้เพิ่มเติม ฉันหวังว่านี่จะเป็นประโยชน์กับผู้อื่นที่มีปัญหาในการเข้าใจวิธีแก้ไขปัญหานี้ (โดยบังเอิญฉันไม่มีคะแนนอินเทอร์เน็ตพอที่จะแสดงความคิดเห็นในคำตอบที่นำไปสู่คำถามนี้ได้โปรดทำอย่างอื่น!)

คำถาม

ถ้าผมเข้าใจมันขวาnotificationObjectIDเป็นสำคัญต่างประเทศชี้ไปที่notification_objectตารางและnotificationIDเป็นชี้ต่างประเทศที่สำคัญกับการแจ้งเตือนตาราง ดูเหมือนว่าวัตถุควรเป็น foreign key ที่อ้างถึง ID ของรายการฐานข้อมูลที่มีการแจ้งเตือน (เช่นเหตุการณ์หรือโพสต์ที่เฉพาะเจาะจง) แต่เราไม่ต้องการฟิลด์อื่นเพื่อระบุว่าเป็นตารางใด

ผู้เขียนเขียน

notification_object.object ระบุประเภทการเปลี่ยนแปลงเช่นสตริง "มิตรภาพ" การอ้างอิงจริงไปยังวัตถุที่เปลี่ยนแปลงด้วยข้อมูลเพิ่มเติมที่ฉันพูดถึงอยู่ใน notification_change.notificationObjectID

ซึ่งดูเหมือนจะไม่สมเหตุสมผลสำหรับฉัน วัตถุเป็นสตริง (enum?) และ notificationObjectID เป็นคีย์ต่างประเทศที่อ้างถึงวัตถุที่มีการแจ้งเตือน? แล้วตารางกลางและขวาเชื่อมต่อกันอย่างไร?

ดูเหมือนว่าโต๊ะกลางจะระบุว่าวัตถุใด (หรือชนิดของวัตถุ) ที่มีการแจ้งเตือนเช่นอีเวนต์หรือโพสต์ จากนั้นเราสามารถมีรายการจำนวนมากในnotification_changeซึ่งชี้ไปที่ประเภทวัตถุเดียวกันซึ่งทำให้เราสามารถรวมการแจ้งเตือน (เช่น "ผู้ใช้ 25 คนโพสต์บนวอลล์ของ X) - ดังนั้นความสัมพันธ์ 1: n ระหว่างตารางกลางและขวา

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

คำถามเกี่ยวกับประสิทธิภาพ - พูดว่า John โพสต์ความคิดเห็นเกี่ยวกับกิจกรรมปิกนิกของ Mary ดูเหมือนว่าเราจะต้องทำการค้นหาเพื่อดูว่าnotification_objectมีอยู่แล้วสำหรับปิคนิคของ Mary ก่อนที่เราจะสร้างรายการnotification_change สิ่งนี้จะส่งผลเสียต่อประสิทธิภาพการทำงานหรือไม่เป็นปัญหาหรือไม่ อย่างต่อเนื่องคำถามจากวรรคก่อนหน้านี้วิธีการที่เราจะทราบว่าการแจ้งเตือนการเข้าชี้notification_objectเพื่อ?

คำตอบ:


8

ขอบคุณสำหรับคำถามที่ละเอียดและขอโทษสำหรับความสับสนทั้งหมด - การแสดงความคิดเห็น 1 ปีหลังจากคำตอบแรกนั้นยากและตอนนี้ 3 ปีหลังจาก .. ความคิดเริ่มต้นจางลงและทำให้ฉันสับสนเหมือนกัน แต่ฉันกลัวที่จะแก้ไขสิ่งที่หลุมเพราะฉันไม่ทำงาน ในการจัดเก็บการแจ้งเตือนเกี่ยวกับแบ็กเอนด์ในขณะนี้และไม่แน่ใจว่าฉันตัดสินใจดีโดยไม่ต้องใช้งานจริงหรือไม่

ฉันคิดว่าตอนที่เขียน:

  • ใช่และไม่ใช่การแจ้งเตือนIDเป็นรหัสต่างประเทศการแจ้งเตือน Object ไม่ใช่ คุณต้องมีฟิลด์ FK อื่นเพื่อผูกตารางเข้าด้วยกัน ฉันโทษประสบการณ์ของฉันในการไม่เข้าใจเกี่ยวกับมัน :(
  • ใช่และไม่ใช่ notification_object.object นั้นคลุมเครือเพราะคุณสามารถใช้มันเป็นสตริงหรือสิ่งที่ซับซ้อน (JSON หรือ FK) ในกรณีของฉันมันเป็นเพียงคำนาม

ดังนั้นทุกอย่างขึ้นอยู่กับลักษณะการแจ้งเตือนของคุณ สำหรับกรณีง่ายๆคุณเพียงต้องการเชื่อมโยงการแจ้งเตือนทั้งหมดไปยัง URL บางอย่างเช่นหน้าเพื่อน - นั่นเป็นเหตุผลว่าทำไมการมีออบเจ็กต์ (entityType) เป็นสตริงจึงมีประโยชน์ - คุณผูก URL เข้ากับมัน

การแจ้งเตือน "คุณมีคำขอเป็นเพื่อน 3 คนเพิ่ม" สามารถจัดเก็บแตกต่างกันได้

หากคุณต้องการแสดงครั้งละหนึ่งรายการคุณจะมีการแจ้งเตือน 3 รายการวัตถุแจ้งเตือน 3 รายการ (friend_request) และ 3 รายการใน notification_change ลิงก์ไปยังผู้ใช้เพื่อนที่เฉพาะเจาะจง

หากคุณต้องการแสดงการแจ้งเตือนหนึ่งรายการคุณจะมีการแจ้งเตือน 1 รายการวัตถุ 1 รายการขึ้นไปและการกระทำ 3 รายการขึ้นไป ดังนั้นในกรณีที่ซับซ้อนเช่น«คุณมี 3 คำขอเป็นเพื่อนจากผู้ใช้ A, ผู้ใช้ B, ผู้ใช้ C » - คุณใช้การแจ้งเตือน ObjectIDs สำหรับผู้ใช้แต่ละคนและมีลิงก์หลายลิงก์ในข้อความแจ้งเตือนของคุณ

คุณควรใช้ 1 หรือ 3 วัตถุ friend_request? ขึ้นอยู่กับ

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

ป้อนคำอธิบายรูปภาพที่นี่

  1. คุณสามารถลบการแจ้งเตือนหรือคุณต้องการประวัติ? ดังนั้นหากฉันส่งคำขอเป็นเพื่อนแล้วยกเลิกหรือแสดงความคิดเห็นแล้วลบบทความเช่นเดียวกับสิ่งที่แตกต่างออกไป - มันควรแสดงประวัตินี้ (เป็นการกระทำอื่น) ให้กับผู้ใช้เป็นสองการกระทำที่แตกต่างกันหรือไม่ อาจจะไม่. นอกจากนี้แล้วมันมีความซับซ้อนมากขึ้นในด้านเทคนิค - คุณต้องค้นหาว่ามี notification_object อยู่หรือไม่ให้เพิ่ม notification_change ใหม่ลงในนั้น (ถ้าไม่ใช่ - เพิ่มวัตถุใหม่) เพื่อที่ในภายหลังฉันจะต้องค้นหาผ่าน notification_change เพื่อลบออก แต่ฉันจะเพิ่ม notification_object อีกอันลงในการแจ้งเตือนเดียวกันและลบออกถ้าการกระทำที่ได้รับการลบถูกลบไปแล้ว

ในทางกลับกันอาจมีหลายกรณีที่อาจมีประโยชน์ในการจัดกลุ่มการกระทำที่ไม่มีสิ่งใดถูกลบออกจากประวัติศาสตร์

ฉันคิดว่านั่นเป็นเหตุผลว่าทำไมในขณะที่เขียนความสัมพันธ์ 1: n ระหว่างตารางด้านซ้ายและกลางจึงทำได้เพื่อให้คุณสามารถจัดกลุ่มการแจ้งเตือนไม่เพียง แต่โดยนักแสดงในเอนทิตีเดียวกัน (ตารางกลางขวา) แต่โดยวัตถุ / เอนทิตี้หลายรายการ

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

เพื่อให้มันดูเหมือนเป็นแบบนี้ ..

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
notification       notification_object      notification_change 
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
ID           ║←—n:1—║ID                 ║—1:n—→║ID                  
noteObjFK          entityType               noteObjFK           
viewerUserID       entityID                 actionOnEntity      
╚═════════════╝      ╚═══════════════════╝      actorUserID         
                                                ╚════════════════════╝

หวังว่านี่จะช่วยได้


เยี่ยมมากขอบคุณสำหรับคำตอบอย่างละเอียดนี้ ฉันจะผ่านมันและแจ้งให้คุณทราบหากฉันมีคำถามเพิ่มเติมอีก แต่ฉันคิดว่านี่จะอธิบายสิ่งต่าง ๆ ได้ดีมาก
user45623
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.