คีย์ต่างประเทศใน Mongo?


98

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

ฉันจะออกแบบโครงร่างนี้ใน MongoDB ได้อย่างไร ฉันคิดว่าไม่มีคีย์ต่างประเทศ!


10
คุณกำลังคิดในเชิงสัมพันธ์แทนที่จะเน้นเอกสาร : P
Pat

6
ทำไมคุณถึงใช้ MongoDB ถ้าคุณต้องการฐานข้อมูลเชิงสัมพันธ์?
Adam Robinson

49
: D ฉันกำลังพยายามทำความเข้าใจวิธีการที่เน้นเอกสาร ฉันจะแก้ปัญหานี้ได้อย่างไร?
Mark Pegasov

หากคุณต้องการคำตอบวิธีเอกสารเชิงของการคิดดูstackoverflow.com/a/18637581/80428 คำตอบที่ยอมรับในปัจจุบันใช้งานได้ แต่เป็นฐานข้อมูลเชิงสัมพันธ์ของ shoehorning ไปยังที่เก็บเอกสารซึ่งไม่ใช่สิ่งที่ NoSQL เกี่ยวกับ
Jay Wick

คำตอบ:


27

คุณอาจสนใจใช้ ORM เช่น Mongoid หรือ MongoMapper

http://mongoid.org/docs/relations/referenced/1-n.html

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

สิ่งที่ Mongoid และ MongoMapper ทำคือให้วิธีการที่สะดวกในการสร้างความสัมพันธ์ที่ค่อนข้างง่าย ตรวจสอบลิงค์ที่ฉันให้คุณและถามอะไรก็ได้

แก้ไข:

ใน mongoid คุณจะเขียนโครงร่างของคุณดังนี้:

class Student
  include Mongoid::Document

    field :name
    embeds_many :addresses
    embeds_many :scores    
end

class Address
  include Mongoid::Document

    field :address
    field :city
    field :state
    field :postalCode
    embedded_in :student
end

class Score
  include Mongoid::Document

    belongs_to :course
    field :grade, type: Float
    embedded_in :student
end


class Course
  include Mongoid::Document

  field :name
  has_many :scores  
end

แก้ไข:

> db.foo.insert({group:"phones"})
> db.foo.find()                  
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }
{ "_id" : ObjectId("4df6540fe90592692ccc9941"), "group" : "phones" }
>db.foo.find({'_id':ObjectId("4df6539ae90592692ccc9940")}) 
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }

คุณสามารถใช้ ObjectId นั้นเพื่อสร้างความสัมพันธ์ระหว่างเอกสาร


มีเอกสารพร้อมรายการและฉันต้องการผูกมัดเมือง ฉันสร้างคอลเลคชันกับเมือง แต่ฉันไม่รู้วิธีผูกเมืองกับไอเท็ม ปล. ขอโทษสำหรับภาษาอังกฤษที่ไม่ดีของฉัน
Mark Pegasov

UPD. ฉันใช้ PHP เป็นภาษาโปรแกรมฉันจะใช้ mongoid ได้อย่างไรถ้ามันเขียนด้วย Ruby
Mark Pegasov

1
@ ЖирайрКазаросян: โอ้ฉันเข้าใจแล้ว :) การเป็นนักพัฒนา Ruby ทำให้ฉันคิดถึง แต่ Ruby :) ฉันกลัวว่าฉันไม่มีประสบการณ์กับ PHP และ Mongo แต่คุณสามารถตรวจสอบลิงค์นี้: mongodb.org/display/DOCS/ …
Nerian

1
@ ЖирайрКазаросян: ฉันเรียนรู้ Ruby on Rails ด้วยหนังสือการพัฒนาเว็บด้วย Ruby on Rails โดยโปรแกรมเมอร์ที่ใช้งานได้จริง นอกจากนี้คุณยังจะได้รับการแนะนำฟรีกับ screencast นี้codeschool.com/courses/rails-for-zombies
Nerian

2
สำหรับผู้อ่านในภายหลัง "ตาราง" คือ "คอลเล็กชัน" ใน MongoDB แถวคือเอกสารและคอลัมน์คือฟิลด์ ... ในกรณีที่คุณสับสน
cpu_meltdown

65

จะออกแบบโต๊ะแบบนี้ใน mongodb ได้อย่างไร?

ก่อนอื่นต้องชี้แจงหลักการตั้งชื่อบางประการ MongoDB ใช้collectionsแทนtables.

ฉันคิดว่าไม่มีคีย์ต่างประเทศ!

ใช้โมเดลต่อไปนี้:

student
{ 
  _id: ObjectId(...),
  name: 'Jane',
  courses: [
    { course: 'bio101', mark: 85 },
    { course: 'chem101', mark: 89 }
  ]
}

course
{
  _id: 'bio101',
  name: 'Biology 101',
  description: 'Introduction to biology'
}

รายการหลักสูตรของ Jane ชี้ไปที่หลักสูตรเฉพาะบางหลักสูตร ฐานข้อมูลไม่ได้ใช้ข้อ จำกัด ใด ๆ กับระบบ ( เช่นข้อ จำกัด ของคีย์ต่างประเทศ ) ดังนั้นจึงไม่มี "การลบแบบเรียงซ้อน" หรือ "การอัปเดตแบบเรียงซ้อน" อย่างไรก็ตามฐานข้อมูลมีข้อมูลที่ถูกต้อง

นอกจากนี้ MongoDB ยังมีมาตรฐาน DBRefที่ช่วยสร้างมาตรฐานในการสร้างข้อมูลอ้างอิงเหล่านี้ อันที่จริงถ้าคุณดูที่ลิงค์นั้นก็มีตัวอย่างที่คล้ายกัน

ฉันจะแก้ปัญหานี้ได้อย่างไร?

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


2
โอเค แต่ฉันจะรับข้อมูลชื่อสนามจากคอลเล็กชันของนักเรียนได้อย่างไร db.student.find () จะส่งคืนบางอย่างเช่นหลักสูตร: [{course: 'bio101', mark: 85}]
Mark Pegasov

@ ЖирайрКазаросян:> db.foo.find ({'_ id': ObjectId ("4df6539ae90592692ccc9940")}) -------------> {"_id": ObjectId ("4df6539ae90592692ccc9940"), "group": "phones"}
Nerian

จาก mongo doc เกี่ยวกับ DBREF: "หากคุณไม่มีเหตุผลที่น่าสนใจในการใช้ DBRef ให้ใช้การอ้างอิงด้วยตนเองแทน"
kroiz

23

เราสามารถกำหนดสิ่งที่เรียกว่าforeign keyใน MongoDB แต่เราจำเป็นต้องรักษาความสมบูรณ์ของข้อมูลด้วยตัวเอง ตัวอย่างเช่น,

student
{ 
  _id: ObjectId(...),
  name: 'Jane',
  courses: ['bio101', 'bio102']   // <= ids of the courses
}

course
{
  _id: 'bio101',
  name: 'Biology 101',
  description: 'Introduction to biology'
}

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

หากหลักสูตรbio101ถูกลบออกเราจำเป็นต้องดำเนินการอื่นเพื่ออัปเดตcoursesฟิลด์ในstudentเอกสาร

เพิ่มเติม: MongoDB Schema Design

ลักษณะการพิมพ์เอกสารของ MongoDB สนับสนุนวิธีที่ยืดหยุ่นในการกำหนดความสัมพันธ์ ในการกำหนดความสัมพันธ์แบบหนึ่งต่อกลุ่ม:

เอกสารในตัว

  1. เหมาะสำหรับตัวต่อตัว
  2. ข้อดี: ไม่จำเป็นต้องดำเนินการสอบถามเพิ่มเติมในเอกสารอื่น
  3. ข้อเสีย: ไม่สามารถจัดการเอนทิตีของเอกสารที่ฝังทีละรายการได้

ตัวอย่าง:

student
{
  name: 'Kate Monster',
  addresses : [
     { street: '123 Sesame St', city: 'Anytown', cc: 'USA' },
     { street: '123 Avenue Q', city: 'New York', cc: 'USA' }
  ]
}

การอ้างอิงเด็ก

เช่นเดียวกับstudent/ courseตัวอย่างด้านบน

การอ้างอิงผู้ปกครอง

เหมาะสำหรับหนึ่งต่อ squillions เช่นข้อความบันทึก

host
{
    _id : ObjectID('AAAB'),
    name : 'goofy.example.com',
    ipaddr : '127.66.66.66'
}

logmsg
{
    time : ISODate("2014-03-28T09:42:41.382Z"),
    message : 'cpu is on fire!',
    host: ObjectID('AAAB')       // Reference to the Host document
}

ตามความเป็นจริง a hostคือพาเรนต์ของไฟล์logmsg. การอ้างถึงhostID จะช่วยประหยัดพื้นที่ได้มากเนื่องจากข้อความบันทึกเป็น squillions

อ้างอิง:

  1. 6 กฎของ Thumb สำหรับการออกแบบสคีมา MongoDB: ตอนที่ 1
  2. 6 กฎของ Thumb สำหรับการออกแบบ MongoDB Schema: ตอนที่ 2
  3. 6 กฎของ Thumb สำหรับการออกแบบ MongoDB Schema: ตอนที่ 3
  4. สร้างแบบจำลองความสัมพันธ์แบบหนึ่งต่อกลุ่มพร้อมการอ้างอิงเอกสาร

19

จากThe Little MongoDB Book

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

ดังนั้น,

student
{ 
    _id: ObjectId(...),
    name: 'Jane',
    courses: [
    { 
        name: 'Biology 101', 
        mark: 85, 
        id:bio101 
    },
  ]
}

หากเป็นข้อมูล RESTful API ให้แทนที่รหัสหลักสูตรด้วยลิงก์ GET ไปยังทรัพยากรของหลักสูตร


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

0

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

โปรดดูเอกสารประกอบ https://mongoosejs.com/docs/middleware.html#pre

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