最佳用户表的数据库设计(模型)是什么?

3

我正在使用Google App Engine和Django开发Web应用,但我认为我的问题更普遍。

用户可以创建表格,但表格在数据库中并不是以TABLES的形式表示。这里举个例子:

第一个表格:
表格名称:__________
第一列名称:__________
第二列名称:__________
...

列数不固定,但有一个最大值(例如100)。每列的类型都相同。

第二个表格(选择特定表格后,用户可以填写表格):
列名1:_____________
列名2:_____________
....

我正在使用以下解决方案,但它是错误的:


class Table(db.Model):
    name = db.StringProperty(required=True)

class Column(db.Model):
    name = db.StringProperty(required=True)
    number = db.IntegerProperty()
    table = db.ReferenceProperty(table, collection_name="columns")

class Value(db.Model):
    time = db.TimeProperty()
    column = db.ReferenceProperty(Column, collection_name="values")

当我想要列出一个表格时,我获取其列,并从每个列中获取其值:


    data = []
    for column in data.columns:
        column_data = []
        for value in column.values:
            column_data.append(value.time)
        data.append(column_data)
    data = zip(*data)
我认为问题在于数值的顺序,因为一个列的顺序并不同于其他列。我正在等待这个错误(但至今我从未见过):
所需表格:          实际得到的表格:
a z c                 a e c
d e f                 d h f
g h i                 g z i
更好的解决方案?也许使用ListProperty

3
这个问题表述不是很清晰,你想要的表与你得到的表的性质与你展示的Datastore模型有点含糊。另外,我不确定你是遇到了问题还是只是担心会遇到问题。 - Adam Crossland
问题很简单:用户可以创建一个表。表是用户视为表的东西,但不一定存储在数据库中。用户选择表中有多少列以及它们的名称。用户填充表格数据。表中的每个条目都是相同类型的。用户可以创建多个表。请参见:http://donotmissthebus.appspot.com/path/(现在表中的列被固定为两个:起点和终点,bus*未实现)。我认为我的解决方案不太线性且容易出错。 - Ruggero Turra
这种阻抗不匹配可能表明关系型数据库不是完成此任务的正确工具。您是否考虑过键值存储,例如:“无SQL”数据库或具有API的分布式文件系统? - Wayne Conrad
5个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2
这里有一个数据模型,可能对你有用:
class Table(db.Model):
 name = db.StringProperty(required=True)
 owner = db.UserProperty()
 column_names = db.StringListProperty()

class Row(db.Model):
 values = db.ListProperty(yourtype)
 table = db.ReferenceProperty(Table, collection_name='rows')

我的想法是: 没有必要使用单独的实体来存储列名。由于所有列都具有相同的数据类型,您只需要存储名称,并且它们被存储在列表中的事实给您一个隐式的顺序号。

通过将值存储在Row实体的列表中,您可以使用索引进入column_names属性以查找values属性中的匹配值。

通过将行的所有值一起存储在单个实体中,不存在值出现在其正确顺序之外的可能性。

警告: 如果在填充了数据之后,表格可以添加列,则此模型将无法很好地工作。为使其成为可能,每次添加列时,该表格下的每一行现有数据都必须在其values列表末尾添加一个值。如果能够有效地将字典存储在数据存储区中,则这不会是问题,但列表实际上只能追加。

或者,您可以使用Expando...

另一个可能性是将Row模型定义为Expando,它允许您动态创建实体上的属性。您可以仅为具有值的列设置列值,并且在表中添加列后也不会破坏任何内容:

class Row(db.Expando):
    table = db.ReferenceProperty(Table, collection_name='rows')

    @staticmethod
    def __name_for_column_index(index):
        return "column_%d" % index

    def __getitem__(self, key):
        # Allows one to get at the columns of Row entities with
        # subscript syntax:
        # first_row = Row.get()
        # col1 = first_row[1]
        # col12 = first_row[12]
        value = None
        try:
            value = self.__dict__[Row.__name_for_column_index]
        catch KeyError:
            # The given column is not defined for this Row
            pass
        return value

    def __setitem__(self, key, value):
        # Allows one to set the columns of Row entities with
        # subscript syntax:
        # first_row = Row.get()
        # first_row[5] = "New values for column 5"

        self.__dict__[Row.__name_for_column_index] = value
        # In order to allow efficient multiple column changes,
        # the put() can go somewhere else.
        self.put()

正如我之前所说,这个解决方案很好,但问题在于如何处理空值,例如在一行中并非每个列都填充了数据。 - Ruggero Turra
当您添加新行时,请使用“None”替换未填充的列。 - Adam Crossland

1
为什么不在Value中添加一个IntegerProperty来表示rowNumber,并在添加新值行时递增它,然后通过按rowNumber排序来重构表格呢?

我考虑过这个方案,它解决了我的问题,但我正在寻找完全不同的解决方案。我认为我的问题并不是新问题,很多人已经用更好的方式解决了它。 - Ruggero Turra
我认为你描述的方式是大多数人使用关系数据库的方式,但由于App Engine数据库是无模式的,你可以给Table一个列名列表作为ListProperty,然后有一个包含时间列表的Row类。 - mckeed
是的,但在这种情况下的问题是处理空值。 - Ruggero Turra

0

将数据放入LongBlob中。

数据库的强大之处在于可以搜索和组织数据,以便您只能获取所需部分以提高性能并简化问题:您不需要整个数据库,只需要其中一部分并且快速获取。但据我了解,当您检索用户的数据时,会检索所有数据并进行显示。因此,您不需要以正常的“数据库”方式存储数据。

我建议的是,将单个用户的所有数据简单格式化并存储在单个列中,使用适当的类型(例如LongBlob)。格式将是一个带有类型列和行列表的对象。并且您可以在与数据库通信的任何语言中定义该对象。

您(真实)数据库中的列将为:User int,TableNo int,Table Longblob。 如果user8有3个表,则将具有以下行:

8, 1, objectcontaintingtable1;
8, 2, objectcontaintingtable2;
8, 3, objectcontaintingtable3;

0

如果你的用户的“表”实际上并没有存储在关系型数据库中作为真正的表,那么你将会让自己的生活变得非常困难。找到一些方法来实际创建表,并利用关系型数据库管理系统的强大功能,否则你就是在重新发明一个非常复杂和精密的轮子。


我必须给用户授予CREATE权限吗?我认为这很糟糕。尽管如此,我正在使用Google应用引擎,因此我正在使用模型而不是直接使用数据库。请记住,每个用户都可以创建数百个“表”。 - Ruggero Turra
不一定。让用户将他们的表规范提交给一个存储过程,该存储过程将为他们创建表。该存储过程可以有很多逻辑来处理允许哪种类型的表(以及有多少个),您不需要给最终用户比必须更多的自由。 - Vince Bowdren

0

这是我会使用的概念性想法:

  1. table 这将作为一个字典,存储您的应用程序创建的伪表的结构。它将有两个字段:table_name、column_name、column_order。其中,column_order 将给出列在表中的位置。

  2. data 这将在伪表中存储实际数据。它将有四个字段:row_id、table_name、column_name、column_data。row_id 对于同一行的数据相同,并且对于各种伪表中的数据是唯一的。


这与我的解决方案并没有太大的区别。我只需要一个行 ID,就像 mckeed 所说的那样。 - Ruggero Turra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,