【问题标题】:How to query entities by ID如何通过 ID 查询实体
【发布时间】:2012-12-27 12:41:04
【问题描述】:

我正在尝试按 ID 查询实体,但不包括其父 ID。

这里有一些代码可以帮助解释:

class Book(ndb.Model):
    ...

class User(ndb.Model):
    ...
class Review(ndb.Model):
    ...

当我创建Review 对象时,我将它们的父级设置为用户,并且它们的 ID 与图书 ID 相同:

review = Review(key=ndb.Key('Review', book.key.id(), parent=user.key))

现在我想通过查询了解每本书有多少评论。由于父 ID 不同,因此无法通过完整键进行查询。

我目前使用的解决方法是将图书 ID 存储在 ndb.KeyPropertyndb.IntegerProperty 中,但这实际上是多余的信息,因为评论的 ID 已经相同。

有没有办法只通过键 ID 进行查询,不包括父 ID?

【问题讨论】:

  • 我不认为有官方方式。存储参考属性是个好主意,您可以获得书评,例如:book.reviews。另外,为什么将父母设置为用户而不是书?如果你想删除一本书及其所有评论,你会怎么做?
  • @JimmyKane 书评示例只是我正在做的事情的精简版;我需要这样的父子关系,因为我的应用在一个事务中编辑了很多“评论”,所以它需要锁定用户的实体组才能工作。
  • 锁定用户的实体组,例如确保用户没有被删除或类似的东西?
  • 为什么会有 XG 交易?只有存在父级时,您才能通过 ID 获取实体。您需要父密钥,或者您可以发布实体密钥。您的选择
  • @JimmyKane XG 事务不适用于超过 5 个实体组,或者至少效果不佳,上次我尝试它比单组事务慢得多。此外,只要我将所有评论保存在一个实体组中,数据存储区就会在一次 API 调用中更新所有评论。

标签: google-app-engine app-engine-ndb


【解决方案1】:

您可以使用类似这样的方式通过 ID 进行查询:review = Review.get_by_id(book.key.id())

您设置 ID 的方法仅适用于图书和评论之间存在一对一关系的情况,因为键是唯一的。上述操作只会返回一个实体。

我建议将最常用的查询设置为审查的祖先。我的猜测是,除非您的用户是著名的评论家,否则他的书评所属的书在这里是最相关的。

如果您将评论的父级设置为图书,您可以使用Ancestor queries 来获取所有评论并保证一致性。然后用户可以是评论的属性,您可以简单地按该属性进行过滤。我建议使用 KeyProperty 作为参考。

如果您希望保证用户查询的一致性,请为每个用户保留一份已评论图书的列表(重复 KeyProperty),然后针对评论运行祖先查询,并由该用户过滤。

更新: @JimmyKane 是对的 - get_by_id 根本不起作用,因为它显然需要指定父级,在你的情况下这似乎不太实用。

证明 get_by_id 不起作用的代码:

from flask import Flask

from google.appengine.ext import ndb

app = Flask(__name__)

class User(ndb.Model):
    name = ndb.StringProperty()

class Book(ndb.Model):
    name = ndb.StringProperty()

class Review(ndb.Model):
    name = ndb.StringProperty()

@app.route('/')
def hello_main():
    user = User()
    user.name = 'Test User1'
    user.put()

    book = Book()
    book.name = 'Test Book1'
    book.put()

    review = Review(id=book.key.id(), parent=user.key)
    review.name = 'Test Review1'
    review.put()

    return 'Review saved!'

@app.route('/reviews/')
def reviews():
    book = Book.query(Book.name == 'Test Book1').get()
    user = User.query(User.name == 'Test User1').get()

    if book:
        review = Review.get_by_id(book.key.id(), parent=user.key)
        if review:
            return review.name
        else:
            return 'no review'
    else:
        return 'no books'


if __name__ == "__main__":
    app.run()

这是我推荐的方法的示例代码:

from flask import Flask

from google.appengine.ext import ndb

class User(ndb.Model):
    name = ndb.StringProperty()
    reviews = ndb.KeyProperty(repeated=True)

class Book(ndb.Model):
    name = ndb.StringProperty()

class Review(ndb.Model):
    name = ndb.StringProperty()

app = Flask(__name__)

@app.route('/')
def hello_main():
    user = User()
    user.name = 'Test User1'
    user.put()

    book = Book()
    book.name = 'Test Book1'
    book.put()

    review = Review(parent=book.key)
    review.name = 'Test Review1'
    review.put()

    user.reviews.append(review.key)
    user.put()

    return 'Review saved!'

@app.route('/add_review/')
def add_review():
    book = Book.query(Book.name == 'Test Book1').get()
    user = User.query(User.name == 'Test User1').get()

    if book:
        review = Review(parent=book.key)
        review.name = 'Test Review'
        review.put()

        user.reviews.append(review.key)
        user.put()

        return 'review added'
    else:
        return 'no books'

@app.route('/reviews/')
def reviews():
    book = Book.query(Book.name == 'Test Book1').get()
    user = User.query(User.name == 'Test User1').get()

    if book:
        reviews = Review.query(ancestor=book.key)
        for review in reviews:
            print(review.name)
            print('<br/>')
        return ''
    else:
        return 'no books'


@app.route('/reviews_by_user/')
def reviews_by_user():
    user = User.query(User.name == 'Test User1').get()

    for review_key in user.reviews:
        review = review_key.get()
        print(review.name)
        print('<br/>')
    return ''



if __name__ == "__main__":
    app.run()

【讨论】:

  • 不评论 = Review.get_by_id(book.key.id(), parent=None) ?它不会返回任何东西......
  • @JimmyKane,不知道你在问什么......你能改一下吗?
  • get_by_id 方法不需要父母吗?如果没有给出 parent,则暗示 None。因此,在您的示例中, get_by_id 将返回 0 个结果。
  • 不要以为是这样。文档没有说明此要求:developers.google.com/appengine/docs/python/ndb/…。另外,我正在使用此答案中的示例:stackoverflow.com/questions/10271103/…
  • 再看一遍。 default 是 None 并且还声明:按 ID 返回实体。这实际上只是 Key(cls, id).get() 的简写,这意味着如果您没有完整路径,如果它不是 Root 实体,则无法获取它
猜你喜欢
  • 1970-01-01
  • 2021-01-15
  • 1970-01-01
  • 2018-09-26
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2015-08-07
相关资源
最近更新 更多