sql >> Databasteknik >  >> NoSQL >> MongoDB

Planera och hantera scheman i MongoDB (även om det är schemalöst)

När MongoDB introducerades var huvudfunktionen som lyftes fram dess förmåga att vara "schemalös". Vad betyder det? Det innebär att man kan lagra JSON-dokument, alla med olika struktur, i samma samling. Det här är ganska coolt. Men problemet börjar när du behöver hämta dokumenten. Hur vet man att ett hämtat dokument har en viss struktur, eller om det innehåller ett visst fält eller inte? Du måste gå igenom alla dokument och söka efter just det fältet. Det är därför det är användbart att noggrant planera MongoDB-schemat, speciellt för de stora applikationerna.

När det gäller MongoDB finns det inget specifikt sätt att designa schemat. Allt beror på din applikation och hur din applikation kommer att använda data. Det finns dock några vanliga metoder som du kan följa när du utformar ditt databasschema. Här kommer jag att diskutera dessa metoder och deras för- och nackdelar.

En-till-få-modellering (inbäddning)

Denna design är ett mycket bra exempel på att bädda in dokument. Betrakta det här exemplet på en personsamling för att illustrera denna modellering.

{
  name: "Amy Cooper",
  hometown: "Seoul",
  addresses: [
    { city: 'New York', state: 'NY', cc: 'USA' },
    { city: 'Jersey City', state: 'NJ', cc: 'USA' }
  ]
}

Fördelar:

  • Du kan få all information i en enda fråga.

Nackdelar:

  • Inbäddad data är helt beroende av det överordnade dokumentet. Du kan inte söka i den inbäddade informationen oberoende av varandra.
  • Tänk på exemplet där du skapar ett uppgiftsspårningssystem med detta tillvägagångssätt. Sedan kommer du att bädda in alla uppgifter som är specifika för en person i personsamlingen. Om du vill avfyra en fråga som:Visa mig alla uppgifter som har morgondagen som deadline. Detta kan vara mycket svårt, även om det är en enkel fråga. I det här fallet bör du överväga andra tillvägagångssätt.

En-till-många-modellering (referensering)

I denna typ av modellering kommer det överordnade dokumentet att innehålla referens-ID (ObjectID) för de underordnade dokumenten. Du måste använda applikationsnivåkopplingar (kombinera två dokument efter att ha hämtat dem från DB på applikationsnivå) för att hämta dokument, så ingen databasnivå ansluts. Därför kommer belastningen på en databas att minska. Tänk på det här exemplet:

// Parts collection
{
  _id: ObjectID(1234),
  partno: '1',
  name: ‘Intel 100 Ghz CPU',
  qty: 100,
  cost: 1000,
  price: 1050
}
// Products collection
{
  name: 'Computer WQ-1020',
  manufacturer: 'ABC Company',
  catalog_number: 1234,
  parts: [
    ObjectID(‘1234’), <- Ref. for Part No: 1
    ObjectID('2345'),
    ObjectID('3456')
  ]
}

Anta att varje produkt kan ha flera tusen delar kopplade till sig. För denna typ av databas är referens den idealiska typen av modellering. Du lägger referens-id:t för alla tillhörande delar under produktdokument. Sedan kan du använda sammanfogningar på applikationsnivå för att få delarna till en viss produkt.

Fördelar:

  • I den här typen av modellering är varje del ett separat dokument så att du kan tillämpa alla delrelaterade frågor på dessa dokument. Du behöver inte vara beroende av ett överordnat dokument.
  • Mycket lätt att utföra CRUD-operationer (Create, Read, Update, Write) på varje dokument oberoende av varandra.

Nackdelar:

  • En stor nackdel med den här metoden är att du måste utföra en extra fråga för att få deldetaljerna. Så att du kan utföra kopplingar på applikationsnivå med produktdokumentet för att få det nödvändiga resultatet. Så det kan leda till att DB-prestanda minskar.
Severalnines Become a MongoDB DBA - Bringing MongoDB to ProductionLäs om vad du behöver veta för att distribuera, övervaka, hantera och skala MongoDBDownload gratis

En-till-miljonmodellering (föräldrareferenser)

När du behöver lagra massor av data i varje dokument kan du inte använda någon av ovanstående metoder eftersom MongoDB har en storleksbegränsning på 16 MB per dokument. Ett perfekt exempel på denna typ av scenario kan vara ett händelseloggningssystem som samlar in loggar från olika typer av maskiner och lagrar dem i Loggar och Maskinsamlingar.

Här kan du inte ens tänka på att använda inbäddningsmetoden som lagrar all logginformation för en viss maskin i ett enda dokument. Detta beror på att dokumentstorleken på bara några timmar kommer att vara mer än 16 MB. Även om du bara lagrar referens-ID för alla loggdokument, kommer du fortfarande att förbruka gränsen på 16 MB eftersom vissa maskiner kan generera miljontals loggmeddelanden på en enda dag.

Så i det här fallet kan vi använda föräldrareferensmetoden. I detta tillvägagångssätt, istället för att lagra referens-ID för underordnade dokument i det överordnade dokumentet, kommer vi att lagra referens-ID:t för det överordnade dokumentet i alla underordnade dokument. Så för vårt exempel kommer vi att lagra ObjectID för maskinen i Logs-dokument. Tänk på det här exemplet:

// Machines collection
{
  _id : ObjectID('AAA'),
  name : 'mydb.example.com',
  ipaddr : '127.66.0.4'
}
// Logs collection
{
  time : ISODate("2015-09-02T09:10:09.032Z"),
  message : 'WARNING: CPU usage is critical!',
  host: ObjectID('AAA')       -> references Machine document
}

Anta att du vill hitta de senaste 3000 loggarna för maskin 127.66.0.4:

machine = db.machines.findOne({ipaddr : '127.66.0.4'});
msgs = db.logmsg.find({machine: machine._id}).sort({time : -1}).limit(3000).toArray()

Tvåvägsreferens

I det här tillvägagångssättet lagrar vi referenserna på båda sidor, vilket innebär att förälders referens lagras i underordnat dokument och barnets referens kommer att lagras i överordnat dokument. Detta gör det relativt enkelt att söka i en till många modellering. Till exempel kan vi söka på både överordnade och uppgiftsdokument. Å andra sidan kräver detta tillvägagångssätt två separata frågor för att uppdatera ett dokument.

// person
{
  _id: ObjectID("AAAA"),
  name: "Bear",
  tasks [ 
    ObjectID("AAAD"),
    ObjectID("ABCD"), -> Reference of child document
    ObjectID("AAAB")
  ]
}
// tasks
{
  _id: ObjectID("ABCD"),
  description: "Read a Novel",
  due_date:  ISODate("2015-11-01"),
  owner: ObjectID("AAAA") -> Reference of parent document
}

Slutsats

I slutändan beror allt på dina applikationskrav. Du kan designa MongoDB-schemat på ett sätt som är mest fördelaktigt för din applikation och ger dig hög prestanda. Här är några sammanfattade överväganden som du kan tänka på när du utformar ditt schema.

  1. Designa schemat baserat på din applikations dataåtkomstmönster.
  2. Det är inte nödvändigt att bädda in dokument varje gång. Kombinera dokument endast om du ska använda dem tillsammans.
  3. Överväg att duplicera data eftersom lagring är billigare än datorkraft nuförtiden.
  4. Optimera schemat för mer frekvent användning.
  5. Arrayer bör inte växa utanför gränsen. Om det finns fler än ett par hundra underordnade dokument, bädda inte in det.
  6. Föredrar kopplingar på applikationsnivå framför kopplingar på databasnivå. Med korrekt indexering och korrekt användning av projektionsfält kan det spara mycket tid.

  1. Hur man sorterar mongodb med pymongo

  2. Java, MongoDB:Hur uppdaterar man varje objekt samtidigt som man itererar en enorm samling?

  3. Tillkännager ClusterControl 1.7.1:Stöd för PostgreSQL 11 och MongoDB 4.0, förbättrad övervakning

  4. Hur loggar man frågorna som körs av Spring Data MongoDB?