1

I have the following query in my application

query = cls.query().filter(cls.taskgroup_id == taskgroup_id, cls.availability == True, cls.task_id > min_task_id).order(cls.task_id) query.fetch(1)

Above works fine as expected. (Fetches only those entities, which match taskgroup_id, and is available, and task_id > min_task_id)

However, when I break query into multiple statements.

query = cls.query()
query.filter(cls.taskgroup_id == taskgroup_id)
query.filter(cls.availability == True)
query.filter(cls.task_id > min_task_id)

It doesn't work as expected.

When I run [2], query formation broken down into multiple statements, it returns me a entity whose availability is False, and task_id is equal to min_task_id.

[2] doesn't work as expected (or as I expect). I think there is a user error here. Wondering what it is.

Dan McGrath
  • 41,220
  • 11
  • 99
  • 130
user462455
  • 12,838
  • 18
  • 65
  • 96

1 Answers1

2

From Filtering by Property Values (emphasis mine):

query = Account.query(Account.userid >= 40, Account.userid < 50)

[...]

Instead of specifying an entire query filter in a single expression, you may find it more convenient to build it up in steps: for example:

appengine/standard/ndb/queries/snippets.py

query1 = Account.query()  # Retrieve all Account entitites
query2 = query1.filter(Account.userid >= 40)  # Filter on userid >= 40
query3 = query2.filter(Account.userid < 50)  # Filter on userid < 50 too

query3 is equivalent to the query variable from the previous example. Note that query objects are immutable, so the construction of query2 does not affect query1 and the construction of query3 does not affect query1 or query2.

In other words for your example none of the query.filter() statements actually modifies query.

Just assign the results of the statements to local variables and use those instead, just as in the quoted example.

Dan Cornilescu
  • 39,470
  • 12
  • 57
  • 97
  • Interesting. Didn't know query objects were immutable. Wonder what the rationale behind that is. Assigning results to temporary variables (though solves the problem), makes it ugly in my opinion ( i might be wrong, and there is a good reason to do that, i guess). – user462455 Nov 19 '16 at 06:21
  • For one it gives the ability to contruct one or more related queries with one or more filters added conditionally (for example filters configurable and selectable by the user via GUI). If the query wouldn't be immutable queries would have to built from scratch all over the place in a potentially complex conditional logic - non-DRY and more error prone IMHO. – Dan Cornilescu Nov 19 '16 at 06:32
  • Interesting. I thought, advising to create temp variables, because of immutability is just as error prone. It is very common to see bugs where query1 will be used instead of query2 (query3 = query1.filter(*) instead of query2.filter(*). And since it is a logical bug, debugging will take more time than expected. Would be better if they provide a mutable query object, just like Java provides StringBuilder(mutable), along with String(immutable) – user462455 Nov 19 '16 at 06:45
  • If you don't plan on reusing any of the intermediate queries, then just use the same variable name each time. – Greg Nov 19 '16 at 09:21