如何比较 NDB 查询中的多个日期?

How to compare multiple dates on an NDB query?

我需要获取 NDB queries 上匹配给定开始和结束日期的对象,但我无法执行这个传统上简单的查询,因为 NDB 抱怨:

from google.appengine.ext import ndb
from datetime import datetime
from server.page.models import Post

now = datetime.now()
query = Post.query(
    Post.status == Post.STATUS_ACTIVE,
    Post.date_published_start <= now,
    Post.date_published_end >= now,
)
count = query.count()

错误:

BadRequestError: Only one inequality filter per query is supported.
Encountered both date_published_start and date_published_end

是否有任何解决方法?

由于每个查询限制单个不等式过滤器的限制,不可能动态获取可直接用于分页而无需任何进一步处理的单个结果列表。相关 GAE 4301 issue.

正如 Jeff 所提到的,通过一个不等式(理想情况下是最严格的不等式)进行过滤,然后对结果进行进一步的动态处理始终是一种选择,如您所指出的那样效率低下,但如果您需要完全灵活的搜索,则这是不可避免的。

您可以通过使用 projection query 来提高性能 - 减少从数据存储传输到相关属性的数据量。

您也可以尝试执行 2 keys-only queries,每个不等式一个,然后计算结果的交集 - 这可以更快地为您提供分页计数和实体列表(作为键)。最后,您将通过直接键查找页面列表中的键来获取当前页面的实体,最好是批处理(使用 ndb.get_multi())。

根据您的预期用途,在某些情况下您可能有其他选择(当然需要额外的工作)。

您可以限制查询的范围。在某些情况下,不是查询所有 Post 个实体,因为时间的开始可能只是某一年或某月的结果就足够了。然后您可以添加 year and/or month Post 属性,您可以将其作为相等过滤器包含在查询中,从而可能将要动态处理的结果数量从数千减少到,比如说,数百或更少。

您还可以完全避免对典型的、经常使用的案例进行查询。例如,如果预期用途是生成几种月度报告,您可以有一些 Report 实体包含每个此类报告 kind/month 的 Post 键列表,您可以在 [= =11=]实体的相关属性发生变化。您无需为报告查询 Posts 实体,而只需使用来自相应 Report 实体的可用列表。您还可以 store/cache 生成实际报告,以便直接重复使用(而不是在每次访问时重新生成)。

使用多个过滤器和不等式进行查询的另一种解决方法是使用搜索 API。 https://cloud.google.com/appengine/training/fts_adv/lesson1#query_options

来自文档:

For example, the query job tag:"very important" sent < 2011-02-28 finds documents with the term job in any field, and also contain the phrase very important in a tag field, and a sent date prior to February 28, 2011.

只需将 Datastore 查询中的数据放入搜索文档中,然后 运行 您对这些文档的查询。