"Only ancestor queries are allowed inside transactions"

1,131 views
Skip to first unread message

Will

unread,
Nov 7, 2009, 11:04:20 PM11/7/09
to google-a...@googlegroups.com
Hi all,

I got this error when I tried to run a query in a transaction, "Only ancestor queries are allowed inside transactions".

I have a class, C1, whose entities have no ancestors. I want to query a particular entity from it, modify, and put it back, for example,

item = C1.gql("WHERE p1 = :a AND p2 = :b ORDER BY p2", a = None, b = 23).fetch(1)
item.p1 = sth
item.put()

The above code should run in a transaction. What should I do?

Thanks in advance.

Will
           

Tonny

unread,
Nov 9, 2009, 4:15:50 AM11/9/09
to Google App Engine
what is the type of p2 and sth?

Nick Johnson (Google)

unread,
Nov 9, 2009, 5:58:21 AM11/9/09
to google-a...@googlegroups.com
Hi Will,

As the error message says, the only queries you can execute inside a transaction are ancestor queries. You need to execute the query outside the transation then, if necessary, check the preconditions still hold inside the transaction.

-Nick Johnson
--
Nick Johnson, Developer Programs Engineer, App Engine
Google Ireland Ltd. :: Registered in Dublin, Ireland, Registration Number: 368047

Will

unread,
Nov 12, 2009, 9:27:19 PM11/12/09
to google-a...@googlegroups.com
The type of p1, p2 and sth is datetime.

Can you give me some examples of 'ancestor queries'? If possible, I'd like to change the existing ones into 'ancestor queries' and fit the whole into a transaction, because that is exactly what a transaction designed for.

Thanks,

Will

--~--~---------~--~----~------------~-------~--~----~

You received this message because you are subscribed to the Google Groups "Google App Engine" group.
To post to this group, send email to google-a...@googlegroups.com
To unsubscribe from this group, send email to google-appengi...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/google-appengine?hl=en
-~----------~----~----~----~------~----~------~--~---


Stephen

unread,
Nov 13, 2009, 8:44:12 AM11/13/09
to Google App Engine
On Nov 13, 2:27 am, Will <vocalster....@gmail.com> wrote:
>
> Can you give me some examples of 'ancestor queries'? If possible, I'd like
> to change the existing ones into 'ancestor queries' and fit the whole into a
> transaction, because that is exactly what a transaction designed for.


http://code.google.com/appengine/docs/python/datastore/transactions.html#What_Can_Be_Done_In_a_Transaction

Will

unread,
Nov 13, 2009, 9:35:12 PM11/13/09
to google-a...@googlegroups.com
Yes, I've read the document. I'm looking for some examples.

As I said, I have a class, C1, whose entities have no ancestors. I want to query a particular entity from it, modify, and put it back, for example,

item = C1.gql("WHERE p1 = :a AND p2 < :b ORDER BY p2", a = None, b = today).fetch(1)
item.p1 = now
item.put()

Both p1 and p2 are datetime. How can I build this into a transaction? Is there a way I can give the entities a 'place holder' ancestor so I can later use an 'ancestor filter' in the query to satisfy the requirement?

Thanks,

Will


--

You received this message because you are subscribed to the Google Groups "Google App Engine" group.
To post to this group, send email to google-a...@googlegroups.com.
To unsubscribe from this group, send email to google-appengi...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-appengine?hl=.



风笑雪

unread,
Nov 14, 2009, 12:24:24 AM11/14/09
to google-a...@googlegroups.com
Why you need a transaction to update just one entity? Just save it and
you may get an exception when update failed.

BTW, DateTimeProperty has an parameter auto_now, you can use it to
automatic update its time by datastore.

And if you really want a transaction, you need fetch it before start
the transaction:

item = C1.gql("WHERE p1 = :a AND p2 < :b ORDER BY p2", a = None, b =
today).get()
if item:
key = item.key()
def update_time(key)
item = C1.get(key)
if item:
item.p1 = now
item.put()
db.run_in_transaction(update_time, key)

2009/11/14 Will <vocals...@gmail.com>:

Will

unread,
Nov 14, 2009, 10:29:25 PM11/14/09
to google-a...@googlegroups.com
I want to find that particular entity, change it and save it back. When one request is doing this, I don't want another request pick up the same entity and modify it again. In short, I want the 'seek-change-save' to be serialized, as one reason the GAE transaction is designed for. Finding out the key of the entity first out of a transaction and then using the key inside the transaction defeats the purpose.

Will

Eli Jones

unread,
Nov 15, 2009, 12:20:26 AM11/15/09
to google-a...@googlegroups.com
you should read the section here:


where they show an example of iterating a counter in a transaction.

If you don't already know the key for the object... then you sort of need to get it to run your transaction.  In the decrement example, they grab the entity first so that they can send the entity key to the decrement function.

Now, if you want to modify their decrement function to see if it works by getting the key inside of the transaction..  then just try that.. it's only a few lines of code.

Eli Jones

unread,
Nov 15, 2009, 12:57:17 AM11/15/09
to google-a...@googlegroups.com
Nevermind, I see what you mean.

So you want a lock on the entity once you know it exists (and satisfies your where clause).

..since something might have come along and updated the p1 column from None to Something before your transaction began.. and thus the key would refer to an entity that does not satisfy your where clause anymore.

If you were willing to let whoever got to it first to update the p1 column.. you could have your transaction verify that p1 was still None once it got the entity inside of the transaction.

If p1 had changed.. then just do nothing since another transaction already won the race.

I think that would work just the same.  Because, assume you have two processes looking for an entity where p1 = None and p2 = Today.. and they each really, really want to update p1 to some value.

One of the processes must win in your scenario.. you just don't want the other one to re-update the entity since it has already been updated.. and p1 <> None.  Now, you still need the transaction of course.. but just add a check after grabbing the entity to verify that p1 = None before doing any updates.

Will

unread,
Nov 16, 2009, 10:58:33 PM11/16/09
to google-a...@googlegroups.com
Thanks Eli. Your solution solves one issue. But ideally, I want the 2nd concurrent request, after waiting, pick up the next item in queue and process, without complicating the code. After all, that's what a transaction is designed for.

Reading another post, it seems one has to create a dummy parent entity for those entities you want to query in a transaction. What I'm looking for is a guide with good examples for querying (otherwise) root entities in a transaction.

Will
Reply all
Reply to author
Forward
0 new messages