Python 多对多关系中的解引用模型
在我的模式中,如下面的测试数据生成示例所述,我想知道一种好方法: 将具有引用键的收藏夹的所有实例取消引用到已删除图片的实例。只需删除任何链接到已删除图片的收藏夹Python 多对多关系中的解引用模型,python,google-app-engine,many-to-many,dereference,app-engine-ndb,Python,Google App Engine,Many To Many,Dereference,App Engine Ndb,在我的模式中,如下面的测试数据生成示例所述,我想知道一种好方法: 将具有引用键的收藏夹的所有实例取消引用到已删除图片的实例。只需删除任何链接到已删除图片的收藏夹 Person类是一个用户 Picture类是最受欢迎的课程 favorite类是具有多对多关系的链接模型方式的一个示例 为什么要问这个问题? 首先,我希望它不会超出这里的范围,第二,因为这可能发生,第三,因为它很有趣 怎么做? 假设一个人可以有多达数千个最喜欢的东西,比如喜欢在社交网络上,或者更糟糕的是,在科学应用程序中,订单、帐户
类是一个用户Person
类是最受欢迎的课程Picture
类是具有多对多关系的链接模型方式的一个示例favorite
ndb.get()
操作,并且不要在每个收藏夹中迭代
让我们不要把事情复杂化。让我们假设我们只有一个用户受到死宠的折磨。他有一个Person类和stubbed user_id属性'123'
在下面的示例中,您可以使用以下处理程序及其相应的函数
import time
import sys
import logging
import random
import cgi
import webapp2
from google.appengine.ext import ndb
class Person(ndb.Expando):
pass
class Picture(ndb.Expando):
pass
class Favourite(ndb.Expando):
user_id = ndb.StringProperty(required=True)
#picture = ndb.KeyProperty(kind=Picture, required=True)
pass
class GenerateDataHandler(webapp2.RequestHandler):
def get(self):
try:
number_of_models = abs(int(cgi.escape(self.request.get('n'))))
except:
number_of_models = 10
logging.info("GET ?n=parameter not defined. Using default.")
pass
user_id = '123' #stub
person = Person.query().filter(ndb.GenericProperty('user_id') == user_id).get()
if not person:
person = Person()
person.user_id = user_id #Stub
person.put()
logging.info("Created Person instance")
if not self._gen_data(person, number_of_models):
return
self.response.write("Data generated successfully")
def _gen_data(self, person, number_of_models):
first, last = Picture.allocate_ids(number_of_models)
picture_keys = [ndb.Key(Picture, id) for id in range(first, last+1)]
pictures = []
favourites = []
for picture_key in picture_keys:
picture = Picture(key=picture_key)
pictures.append(picture)
favourite = Favourite(parent=person.key,
user_id=person.user_id,
picture=picture_key
)
favourites.append(favourite)
entities = favourites
entities[1:1] = pictures
ndb.put_multi(entities)
return True
class CorruptDataHandler(webapp2.RequestHandler):
def get(self):
if not self._corrupt_data(0.5):#50% corruption
return
self.response.write("Data corruption completed successfully")
def _corrupt_data(self, n):
picture_keys = Picture.query().fetch(99999, keys_only=True)
random_picture_keys = random.sample(picture_keys, int(float(len(picture_keys))*n))
ndb.delete_multi(random_picture_keys)
return True
class FixDataHandler(webapp2.RequestHandler):
def get(self):
user_id = '123' #stub
person = Person.query().filter(ndb.GenericProperty('user_id') == user_id).get()
self._dereference(person)
def _dereference(self, person):
#Here if where you implement your answer
由于中的最终一致性,所以需要单独的处理程序
NDB数据存储。更多信息:
当然,我发布答案也是为了表明我在发布之前尝试了一些东西。ReferenceProperty只是一个键,因此如果你有被删除人的键,你可以使用它来查询收藏夹
否则,没有简单的方法。您必须筛选所有收藏夹,并找到那些有无效图片的收藏夹。它在mapreduce作业中非常简单,但如果您有很多收藏夹,则可能是一个昂贵的查询。您可以使用预删除挂钩(寻找实现它的方法)
当然,如果您使用NDB API而不是数据存储API(),这可能会更容易实现,但是您必须更改引用的方式(谢谢Nizz;-)。我会测试并报告。是的,它只会帮助防止错误链接。如果腐败已经存在……我想不出一个便宜的方法来做到这一点。这就是为什么最好避免这种情况。。。唯一可行的方法(如果您不介意保留损坏的数据,直到看到它们的结果)是在出现时处理错误,即try/except语句,其中您将在try块中有加载部分,在except块中有修复。我确实认为有。例如,如果您只使用密钥,而不使用get进行迭代,但尝试实现联接。我同意,最好的方法是在用户操作时检测到它,并将其添加到任务队列或立即修复它。是的,如果收藏夹是一个小的非昂贵数字,则迭代是最佳方法。但是如果你有50000个收藏夹和99999张图片呢?你必须过滤50000个收藏夹。对于每个收藏夹,请检查图片,如果图片无效,请删除收藏夹。是的,这最终需要花费10万个实体回迁。如果这是一个罕见的(比如说一个月一次或更少)清理操作,那么这并不昂贵。无论怎样,当你删除人物和图片实体时,你都应该清理收藏夹,所以你不需要依赖这种扫描和清理。如果你正在寻找一种更便宜的方法来完成这项工作。。。它不存在(除了预防方法)。你能做的最好的事情就是在“死”收藏夹已经被访问时检查它们(就像用户正在加载页面一样),然后清理它们。然后,您可能不必为了清理而额外读取实体。