it-swarm.com.de

Wie würden Sie eine Benutzerdatenbank mit benutzerdefinierten Feldern entwerfen?

Bei dieser Frage geht es darum, wie ich eine Datenbank entwerfen soll. Es kann sich um relationale/nosql-Datenbanken handeln, je nachdem, welche Lösung die bessere ist


Vorausgesetzt, Sie müssen ein System erstellen, das eine Datenbank zur Verfolgung von "Unternehmen" und "Benutzer" enthält. Ein einzelner Benutzer gehört immer nur einem Unternehmen an

  • Ein Benutzer kann nur einer Firma angehören
  • Ein Unternehmen kann viele Benutzer haben

Das Design für den Tisch "Company" ist recht einfach. Das Unternehmen verfügt über die folgenden Attribute/Spalten: (Lassen Sie es uns einfach halten)

ID, COMPANY_NAME, CREATED_ON

Erstes Szenario

Einfach und unkompliziert haben alle Benutzer das gleiche Attribut, sodass dies problemlos im relationalen Stil (Benutzertabelle) erfolgen kann:

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON

Zweites Szenario

Was passiert, wenn verschiedene Unternehmen unterschiedliche Profilattribute für ihren Benutzer speichern möchten? Jedes Unternehmen verfügt über einen definierten Satz von Attributen, die für alle Benutzer dieses Unternehmens gelten.

Zum Beispiel:

  • Firma A möchte speichern: LIKE_MOVIE (boolean), LIKE_MUSIC (boolean)
  • Firma B möchte speichern: FAV_CUISINE (String)
  • Firma C möchte speichern: OWN_DOG (boolean), DOG_COUNT (int)

Ansatz 1

die Brute-Force-Methode besteht darin, ein einzelnes Schema für den Benutzer zu erstellen und ihm Nullen zu geben, wenn er nicht zum Unternehmen gehört:

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, LIKE_MOVIE, LIKE_MUSIC, FAV_CUISINE, OWN_DOG, DOG_COUNT, CREATED_ON

Das ist ein bisschen böse, weil Sie am Ende viele NULL-Werte und Benutzerzeilen haben, deren Spalten für sie irrelevant sind (dh alle Benutzer von Unternehmen A haben NULL-Werte für FAV_CUISINE, OWN_DOG, DOG_COUNT).

Ansatz 2

ein zweiter Ansatz besteht darin, ein "Freiformfeld" zu haben:

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_1, CUSTOM_2, CUSTOM_3, CREATED_ON

Dies wäre für sich genommen unangenehm, da Sie keine Ahnung haben, was benutzerdefinierte Felder sind. Der Datentyp spiegelt nicht die gespeicherten Werte wider (z. B. speichern wir den int-Wert als VARCHAR).

Ansatz 3

Ich habe mir das PostgreSQL JSON-Feld angesehen. In diesem Fall haben Sie:

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_PROFILE_JSON, CREATED_ON

Wie könnten Sie in diesem Fall verschiedene Schemas auf einen Benutzer anwenden? Ein Benutzer mit Firma A hat ein Schema, das aussieht

 {"LIKE_MOVIE":"boolean", "LIKE_MUSIC": "boolean"}

Während ein Benutzer mit Firma C ein anderes Schema hat:

 {"OWN_DOG ":"boolean", "DOG_COUNT": "int"}

Wie soll ich dieses Problem lösen? Wie kann ich die Datenbank richtig entwerfen, um dieses flexible Schema für ein einzelnes "Objekt" (Benutzer) basierend auf der Beziehung, die sie haben (Firma), zu ermöglichen?

relationale Lösung? NOSQL-Lösung?


Edit : Ich habe auch über eine "CUSTOM_PROFILE" -Tabelle nachgedacht, in der Benutzerattribute im Wesentlichen in Zeilen und nicht in Spalten gespeichert werden.

Bei diesem Ansatz gibt es zwei Probleme:

1) Die Daten wachsen pro Benutzer wachsen als Zeilen und nicht als Spalten - und dies bedeutet, dass viele Verknüpfungen erforderlich sind, um ein vollständiges Bild des Benutzers zu erhalten Dazu werden mehrere Verknüpfungen mit der Tabelle "Benutzerdefiniertes Profil" für die verschiedenen benutzerdefinierten Attribute erstellt

2) Der Datenwert wird immer als VARCHAR gespeichert, um generisch zu sein, auch wenn wir wissen, dass die Daten ganzzahlig oder boolesch sein sollen usw.

21
noobcser

Bitte betrachten Sie dies als Alternative. In den beiden vorherigen Beispielen müssen Sie Änderungen am Schema vornehmen, wenn der Anwendungsbereich wächst. Außerdem ist die Lösung "custom_column" schwer zu erweitern und zu warten. Schließlich werden Sie mit Custom_510 enden und sich dann vorstellen, wie schrecklich es sein wird, mit dieser Tabelle zu arbeiten.

Verwenden wir zunächst Ihr Firmenschema.

[Companies] ComnpanyId, COMPANY_NAME, CREATED_ON

Als Nächstes verwenden wir Ihr Benutzerschema auch für erforderliche Attribute der obersten Ebene, die von allen Unternehmen verwendet/gemeinsam genutzt werden.

[Users] UserId, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON

Als Nächstes erstellen wir eine Tabelle, in der wir unsere dynamischen Attribute definieren, die für die benutzerdefinierten Benutzerattribute jedes Unternehmens spezifisch sind. Ein Beispielwert für die Attributspalte wäre hier also "LikeMusic":

[UserAttributeDefinition] UserAttributeDefinitionId, CompanyId, Attribute

Als Nächstes definieren wir eine UserAttributes-Tabelle, die Benutzerattributwerte enthält

[UserAttributes] UserAttributeDefinitionId, UserId, Value

Dies kann auf viele Arten geändert werden, um die Leistung zu verbessern. Sie können mehrere Tabellen für UserAttributes verwenden, um jede für den in Value gespeicherten Datentyp spezifisch zu machen, oder sie einfach als VarChar belassen und als Schlüsselwertspeicher damit arbeiten.

Möglicherweise möchten Sie CompanyId auch aus der UserAttributeDefiniton-Tabelle in eine Querverweistabelle verschieben, um sie später zu prüfen.

14
P. Roe

Verwenden Sie eine NoSQL-Datenbank. Es würde Firmen- und Benutzerdokumente geben. Die Benutzer würden einen Teil ihres Schemas dynamisch basierend auf einer Benutzervorlage erstellen lassen (Text zur Angabe von Feldern/Typen für diese Firma.

\Company\<uniqueidentifier>
    - Name: <Name>
    - CreatedOn: <datetime>
    - UserTemplate: <Text>

\User\<uniqueidentifier>
    - COMPANY_ID: <ID>
    - FIRST_NAME: <Text>
    - LAST_NAME: <Text>
    - EMAIL: <Text>
    - CREATED_ON: <datetime>
    - * Dynamically created fields per company

So könnte es in so etwas aussehen wie Firebase.com Sie müssten lernen, wie man es in einem beliebigen Fall macht.

7
JeffO

Wenn Sie häufig auf benutzerdefinierte Feldanforderungen stoßen, würde ich diese tatsächlich ziemlich ähnlich wie die Datenbank modellieren. Erstellen Sie eine Tabelle, die die Metadaten zu jedem benutzerdefinierten Feld, CompanyCustomField (wem es gehört, dem Datentyp usw.) und eine andere Tabelle CompanyCustomFieldValues ​​enthält, die die CustomerId, FieldId und den Wert enthält. Wenn Sie so etwas wie Microsoft SQL Server verwenden, muss die Wertespalte ein Datentyp "sql_variant" sein.

Dies ist natürlich nicht einfach, da Sie eine Schnittstelle benötigen, über die Administratoren benutzerdefinierte Felder für jeden Kunden definieren können, und eine andere Schnittstelle, die diese Metadaten tatsächlich zum Erstellen einer Benutzeroberfläche zum Sammeln der Feldwerte verwendet. Wenn Sie andere Anforderungen haben, z. B. das Gruppieren von Feldern oder die Notwendigkeit, eine Auswahlliste zu erstellen, müssen Sie diese mit mehr Metadaten/anderen Tabellen (z. B. CompanyCustomFieldPickListOptions) versehen.

Dies ist nicht trivial, hat jedoch den Vorteil, dass nicht für jedes neue benutzerdefinierte Feld Datenbankänderungen/Codeänderungen erforderlich sind. Alle anderen Funktionen von benutzerdefinierten Feldern müssen ebenfalls codiert werden (z. B. wenn Sie einen Zeichenfolgenwert mit einem regulären Ausdruck validieren oder nur Datumsangaben zwischen bestimmten Bereichen zulassen möchten oder wenn Sie ein benutzerdefiniertes Feld basierend auf einem anderen benutzerdefinierten Feldwert aktivieren müssen ).

3
Andy

Eine Alternative zu den anderen Antworten besteht darin, eine Tabelle mit dem Namen profile_attrib oder eine ähnliche Tabelle zu haben, in der das Schema vollständig von Ihrer Anwendung verwaltet wird.

Wenn benutzerdefinierte Attribute hinzugefügt werden, ALTER TABLE profile_attrib ADD COLUMN like_movie TINYINT(1), können Sie das Löschen dieser Attribute verhindern. Dies würde Ihren Join minimieren und gleichzeitig Flexibilität bieten.

Ich denke, der Kompromiss besteht darin, dass die Anwendung jetzt Tabellenberechtigungen für die Datenbank ändern muss, und Sie müssen klug sein, wenn es darum geht, die Spaltennamen zu bereinigen.

1
Chris Seufert

Ihre Frage hat viele mögliche Lösungen. Eine Lösung besteht darin, die zusätzlichen Attribute als XML zu speichern. Das XML kann als Text gespeichert werden oder wenn Sie eine Datenbank verwenden, die XML-Typen als XML (SQL Server) unterstützt. Das Speichern als Text schränkt Ihre Abfragefähigkeit ein (wie das Suchen nach einem benutzerdefinierten Attribut). Wenn Sie jedoch nur das Speichern und Abrufen benötigen, ist dies eine gute Lösung. Wenn eine Abfrage erforderlich ist, ist das Speichern des XML als XML-Typ eine bessere Option (obwohl dies herstellerspezifischer ist).

Dies gibt einem die Möglichkeit, eine beliebige Anzahl von Attributen für einen Kunden zu speichern, indem lediglich eine Zusatzspalte zur Kundentabelle hinzugefügt wird. Man könnte die Attribute als Hashset oder Wörterbuch speichern, man verliert die Typensicherheit, da alles zunächst eine Zeichenfolge ist, aber wenn man eine Standardformatzeichenfolge für Datumsangaben, Zahlen und Boolesche Werte erzwingt, funktioniert dies in Ordnung.

Für mehr Informationen:

https://msdn.Microsoft.com/en-us/library/hh403385.aspx

Die Antwort von @ WalterMitty ist ebenfalls gültig. Wenn man jedoch viele Kunden mit unterschiedlichen Attributen hat, kann dies zu vielen Tabellen führen, wenn man dem Vererbungsmodell folgt. Dies hängt davon ab, wie viele benutzerdefinierte Attribute von Kunden gemeinsam genutzt werden.

0
Jon Raynor