应用程序引擎允许的筛选器和结果排序详解

139 阅读3分钟

允许的筛选器和结果排序

应用程序引擎允许您在属性值上使用以下操作符:

  • =
  • >
  • >=
  • <
  • <=
  • !
  • in

为了匹配不等式筛选器,将扫描索引以找到第一个匹配行,从该行返回所有连续行,直到一行不匹配。

请记住,索引中的所有行都是按照该属性排序的!可以在单个属性上定义多个不等式筛选器,但不允许在同一查询的不同属性上具有多个不等式筛选器。

单个属性上的多个不等式筛选器被拆分为多个查询,其中结果集在返回之前被合并。所以一个查询如下:

SELECT *FROM Task WHERE start_date>=:a_specified_date

AND start_date <=:another_specified_date

分两部分运行,其中一部分匹配 start_date 大于或等于指定日期的所有行,另一部分匹配 start_date 小于或等于另一个开始日期的所有行。最后,合并两个查询的结果。

当排序涉及不等式筛选器的查询时,需要首先根据应用不等式筛选器运算符的属性进行排序。只有在应用不等式筛选器的属性之后,才能在排序中包含其他属性。

可以在对属性使用不等式筛选运算符的同一查询中使用不同属性上的多个等式筛选运算符。但是,在为此查询定义 ORDERBY 条件时,请记住首先按定义不等式属性的属性对结果进行排序。

数据存储允许属性包含一个值列表的同一属性的不同数据类型。

IN 运算符处理包含列表的值。IN 运算符计算成员。如果列表中有一个元素与筛选器匹配,则在结果中返回一个实体。例如,a_prop = [1,2]将同时匹配 a_prop = 1a_prop = 2

但是,如果查询指定 a_prop > 1a_ prop < 2,则 a_prop = [1,2]将不匹配,因为尽管一个元素匹配任何一个条件,但没有一个元素同时匹配两个条件。

对于包含值列表的多值属性,列表中的每个属性都会添加到索引中。

除了规定的匹配行为之外,在排序时还会产生一些副作用。

多值属性按升序的最小值和降序的最大值排序。因此,当应用升序时,包含[1,3,5,7]的多值属性被视为1,而当应用降序时,相同的属性值被视为7。因此,当涉及到顺序[1,3,5,7]时,它既小于[2,3,4,5,6] ,又大于[2,3,4,5,6]

两个实体可以为同一属性包含不同的数据类型,有些实体甚至可能没有该属性。

当查询基于某个属性进行筛选时,将跳过未定义该属性的实体。

如果希望在结果中包含该实体,那么至少为特定实体中的属性设置一个 null (或者在 Python 中为 Nothing)值。

查询只匹配那些包含与查询筛选器指定的数据类型相同的实体。因此,对字符串值进行匹配的查询将只查找与具有相同字符串类型的实体的匹配

在单个属性中混合数据类型也会在排序时产生一些副作用。数据类型之间的排序有层次结构。例如,整数在浮点数之前排序。因此,按照同时包含整数和浮点值的属性进行排序可能比较棘手,因为5 < 4.5

我之前提到过,每个查询都需要一个索引,查询及其显式定义的索引可以是这样的:

q = db.GqlQuery("SELECT * FROM Task" +
                "WHERE start_date >= :1"+
                "tags IN:2"+
                "ORDER BY start_date",
                datetime.datetime(2011, 1, 1, 12,0, 0).date(),["Important","Sample"])

indexes:

   -kind:Task 

   properties: 

       -name:start_date 
       -name:tags

到目前为止,在这个示例中,已经通过提取方法获得了一个查询结果,方法允许您在单个调用中获取一组记录。返回的结果记录的数量由此限制定义。

如果您只想要一个实体,那么可以使用 get 方法来检索位于订单顶部的实体。 如果您只想知道结果中实体的数量,那么只需使用 count 方法。Count 方法返回结果中所有实体的计数,除非它超时。

应用程序引擎适合快速响应,可以轻松扩展。任何超过30秒的反应。

如果需要遍历整个结果集,则需要使用 Query 接口作为可迭代的对象:

q=db.GqlQuery("SELECT * FROM Task" +

                "WHERE start_date=:1"+ 

                "ORDER BY name", datetime.datetime(2011, 1, 1, 12, 0, 0).date()) 



for task in q:

    print ("Task name: %s" % (task.name))

Taskmanager GAE 项目可迭代对象允许您以小块的形式访问结果集,直到收到所有结果。

尽管可迭代对象允许您遍历整个集合,但是它不允许您以后返回并从最后一次提取开始以增量方式提取。对于这种增量获取,光标是一个合适的特性。读取之后,可以使用查询对象的 cursor 方法获取游标。游标是一个 base64编码的数据指针,允许您以增量方式获取其他结果。

获取增量结果的方法应该与第一种方法相同,只要过滤器、排序顺序

在执行查询之前,您需要将光标传递给查询对象的 with_cursor 方法。

游标不受已获取数据的任何更改的影响。忽略当前游标之前范围内的任何更新或插入。

为了促进一致的数据状态,应用程序引擎支持所有实体和实体组级更新的原子事务。事务完整性意味着操作要么成功,要么回滚。在单个实体的上下文中对数据存储区的所有写操作(即创建、更新和删除操作)都是原子的。

一个实体、它的祖先和它的子实体组成一个实体组。操作实体组中实体的函数可以包含在事务边界内。如果将函数及其参数传递给 db.run_in_action 方法,则函数可以作为事务单元显式运行。

示例:


import datetime

from google.appengine.ext import db

class Task(db.Model):

    name=db.stringProperty(required=True)

    description=db.stringProperty()

    start_date = db.DateProperty(required=True)

    due_date=db.DateProperty()

    end_date=db.DateProperty()

    tags=db.stringListProperty()

    status = db.StringProperty(choices=('in progress', 'complete', 'not started'))

    def update_as_complete(key,status):

        obj=db.get(key)

        if status== "complete":

            obj.status='complete'
            
            obj.end_date=datetime.datetime.now().day() 
            
            obj.put()

            q=db.GqlQuery("SELECT * FROM Task" + 
                          "where name =:1","task1") 
            
            completed_task=q.get()

            db.run_in_transaction(update_as_complete, completed_task.key(), "complete")

应用程序引擎不锁定任何行。不支持跨越两个或更多根实体的操作的事务。


本文正在参加「金石计划 . 瓜分6万现金大奖」