小能豆

我想要几个“包”(Mjbundle),它们本质上是问题包(Mjquestion)

py

我想要几个“包”(Mjbundle),它们本质上是问题包(Mjquestion)。Mjquestion 有一个整数“索引”属性,该属性必须是唯一的,但它应该只在包含它的包中是唯一的。我不确定如何正确地对这样的事情进行建模,我尝试使用下面的结构化(重复)属性来做到这一点,但实际上还没有任何东西可以限制 Mjquestion 索引的唯一性。有什么更好/正常/正确的方法来做到这一点?

class Mjquestion(ndb.Model):
    """This is a Mjquestion."""
    index = ndb.IntegerProperty(indexed=True, required=True)
    genre1 = ndb.IntegerProperty(indexed=False, required=True, choices=[1,2,3,4,5,6,7])
    genre2 = ndb.IntegerProperty(indexed=False, required=True, choices=[1,2,3])
    #(will add a bunch of more data properties later)

class Mjbundle(ndb.Model):
    """This is a Mjbundle."""
    mjquestions = ndb.StructuredProperty(Mjquestion, repeated=True)
    time = ndb.DateTimeProperty(auto_now_add=True)

(使用上述模型并获取了某个 Mjbundle 实体后,我不确定如何根据索引从 mjquestions 中快速获取 Mjquestion。关于结构化属性过滤的解释看起来适用于 Mjbundle 类型级别,而我已经有一个 Mjbundle 实体,并且不确定如何快速查询该实体包含的问题,而无需在代码中“手动”循环遍历它们。)


阅读 25

收藏
2024-12-10

共1个答案

小能豆

你在尝试设计一个包含多个 MjquestionMjbundle 模型时,遇到的问题主要集中在两个方面:

  1. 如何确保 Mjquestion 中的 index 在一个 Mjbundle 内唯一。
  2. 如何从 Mjbundle 中快速检索包含的 Mjquestion,尤其是通过 index 进行检索。

解决方法

1. 确保 Mjquestion.index 在一个 Mjbundle 内唯一

为了确保每个 Mjbundle 内的 Mjquestion 有唯一的 index,你可以通过以下两种方法实现:

  • 在保存 Mjquestion 时检查唯一性
    在将 Mjquestion 添加到 Mjbundle 中时,检查当前包中是否已经存在该 index,如果存在则抛出异常。这是一种“软”保证,确保唯一性,但需要手动检查。

  • 在数据库层面使用事务性检查
    使用 Google Cloud Datastore 的事务(ndb.transaction)来确保在同一时刻,只有一个操作会修改一个 Mjbundle 中的 Mjquestion 列表,这样可以避免并发操作中的唯一性冲突。

2. 快速查询 Mjquestion 通过 index

由于你使用了 ndb.StructuredProperty 来存储 Mjquestion 列表,直接通过 indexMjquestion 内部查询可能会比较低效,因为你必须手动遍历列表进行搜索。如果你希望更高效地查询,你有几个选择:

  1. 使用字典索引
    Mjquestion 组织成一个字典,其中键是 index,这样可以通过键值对直接访问。

```python
class Mjbundle(ndb.Model):
“”“This is a Mjbundle.”“”
mjquestions = ndb.StructuredProperty(Mjquestion, repeated=True)
time = ndb.DateTimeProperty(auto_now_add=True)

   def get_question_by_index(self, index):
       """通过 index 查找 Mjquestion。"""
       question_dict = {q.index: q for q in self.mjquestions}
       return question_dict.get(index, None)

```

这样,你就可以通过 get_question_by_index() 方法,快速通过 index 获取对应的 Mjquestion,而不需要遍历整个列表。

  1. 优化查询模型
    如果你希望能够从 Mjquestion 对象本身进行高效查询,可以考虑将 index 作为一个独立的实体来管理,而不是嵌套在 Mjbundle 中。例如,可以在 Mjquestion 实体中独立管理 Mjbundle 的引用,并且允许按 index 来查询。

```python
class Mjquestion(ndb.Model):
“”“This is a Mjquestion.”“”
index = ndb.IntegerProperty(indexed=True, required=True)
genre1 = ndb.IntegerProperty(indexed=False, required=True, choices=[1,2,3,4,5,6,7])
genre2 = ndb.IntegerProperty(indexed=False, required=True, choices=[1,2,3])
bundle_key = ndb.KeyProperty(kind=Mjbundle) # 关联的 Mjbundle

class Mjbundle(ndb.Model):
“”“This is a Mjbundle.”“”
time = ndb.DateTimeProperty(auto_now_add=True)

   def get_question_by_index(self, index):
       """通过 index 获取 Mjquestion。"""
       question = Mjquestion.query(Mjquestion.bundle_key == self.key, Mjquestion.index == index).get()
       return question

```

这种方式会让你能直接从 Mjquestion 进行高效查询,并且保证 index 在每个 Mjbundle 中唯一(通过 Mjquestion.query 进行查询时,使用 bundle_key 来限定范围)。

3. 完整示例代码

class Mjquestion(ndb.Model):
    """This is a Mjquestion."""
    index = ndb.IntegerProperty(indexed=True, required=True)
    genre1 = ndb.IntegerProperty(indexed=False, required=True, choices=[1, 2, 3, 4, 5, 6, 7])
    genre2 = ndb.IntegerProperty(indexed=False, required=True, choices=[1, 2, 3])
    bundle_key = ndb.KeyProperty(kind='Mjbundle')  # 关联的 Mjbundle

class Mjbundle(ndb.Model):
    """This is a Mjbundle."""
    mjquestions = ndb.StructuredProperty(Mjquestion, repeated=True)
    time = ndb.DateTimeProperty(auto_now_add=True)

    def get_question_by_index(self, index):
        """通过 index 获取 Mjquestion。"""
        question_dict = {q.index: q for q in self.mjquestions}
        return question_dict.get(index, None)

    def add_question(self, question):
        """添加 Mjquestion,确保索引唯一。"""
        if any(q.index == question.index for q in self.mjquestions):
            raise ValueError(f"Index {question.index} already exists in this bundle.")
        self.mjquestions.append(question)
        self.put()  # 保存 Mjbundle

# 示例使用:
bundle = Mjbundle(time=datetime.datetime.now())
bundle.put()

# 创建问题
question1 = Mjquestion(index=1, genre1=2, genre2=1, bundle_key=bundle.key)
question2 = Mjquestion(index=2, genre1=3, genre2=2, bundle_key=bundle.key)

# 将问题添加到包中
bundle.add_question(question1)
bundle.add_question(question2)

# 根据索引查询问题
q = bundle.get_question_by_index(1)
print(q)  # 打印 index 为 1 的问题

结论

  • 使用 Mjquestion.indexMjbundle 内部保持唯一性,可以通过手动检查和事务管理来完成。
  • 使用字典来优化 Mjquestion 查询,避免重复遍历整个列表。
  • 如果查询需求复杂,可以将 Mjquestion 单独建模,使用 bundle_keyindex 查询。
2024-12-10