我有一个这样的模型:
class UserModel(ndb.Model):
''' model class which stores all the user information '''
fname = ndb.StringProperty(required=True)
lname = ndb.StringProperty(required=True)
sex = ndb.StringProperty(required=True, choices=['male', 'female'])
age = ndb.IntegerProperty(required=True)
dob = ndb.DateTimeProperty(required=True)
email = ndb.StringProperty(default=None)
mobile = ndb.StringProperty(required=True)
city = ndb.StringProperty(required=True)
state = ndb.StringProperty(required=True)
由于上述字段均不是唯一的,因此即使是电子邮件,也许很多人可能没有电子邮件ID。所以我使用以下逻辑来创建字符串id
1. Take first two letters of 'state' and change it to upper case.
2. Take first to letters of 'city' and change it to upper case.
3. Get the count of all records in the database and increment by one.
4. Append all of them together.
我使用get_or_insert插入实体。
虽然添加用户,但不会经常发生,但任何类型的冲突都将是灾难性的,意味着争用的可能性较小,但其影响非常大。
我的问题是:
1. Will using get_or_insert guarantee that I will never have duplicate IDs?
2. get_or_insert documentation says "Transactionally retrieves an existing
entity or creates a new one.". How can something perform an operation
"transactionally" without using a ancestor query.
PS:由于多种原因,我无法将所有用户实体保留在同一个实体组中。
答案 0 :(得分:3)
为了提供交易性,get_or_insert
使用Datastore transaction。为了在事务中使用查询,它必须是祖先查询,但是事务也可以是get
和put
,它们不需要在实体上设置父项。
但是,正如@Greg所提到的,您绝对不希望使用此方案来生成用户ID。特别是,对数据库进行计数是非常缓慢的,并且不会扩展,并且最终是一致的。因为查询最终是一致的,所以只要结果最终一致(对于大型应用程序将始终如一),它可以返回小于实际计数的计数。这意味着您可以等待几个小时才能实际插入插件。
如果您想提供州和城市的客户ID,我建议您执行以下操作:
答案 1 :(得分:1)
如果您保留该ID方案(您实际上并不真正需要步骤1和2,只需3步),则没有理由创建重复的ID。使用get_or_insert,它将查找您提供的确切ID并在其存在时获取它,或者只是创建它,如果不存在,如here所述。因此,您不能拥有重复的ID(如果您将此ID作为模型中的强制密钥)。如果你按照提供的链接明确说明:
get和后续(可能的)put操作包含在事务中以确保原子性。这意味着get_or_insert()永远不会覆盖现有实体,并且当且仅当不存在具有给定种类和名称的实体时才会插入新实体。
事实上它处理transactionnaly意味着它将锁定实体组以确保您没有争用。由于你似乎没有祖先,我认为它只会锁定你正在更新的实体