What is the compatible version of this query for NDB? - google-app-engine

Maybe it's wrong but I always use this query for my app:
cme_only = Comput.all().filter('__key__ =', cid.key())
What is the compatible version of this query for NDB?
The Metadata queries are very different..
edit:
cid is an entity and cme_only is an iterable that I'm sure has only one value
cid = Comput.get_by_id(int(self.request.get('id')))
cme_only = Comput.all().filter('__key__ =', cid.key())
and then in template:
{{ for Comput in cme_only }}
I do not like it but it was enough

There's no need for metadata queries. The NDB way to spell a query on __key__ is as follows:
ModelClass.query(ModelClass._key == key_value)
That is, just like querying for property foo is done by filtering on ModelClass.foo == value, ModelClass._key is a pseudo-property representing the key.
The other posters are correct that if you just one a single entity given its full key, using the get() method on the Key object is better (faster and cheaper). Also, if e is an entity (model instance), in NDB, the key is not e.key() but e.key (or e._key -- yes, that's the same _key attribute I mentioned in above, it works as a class attribute and as an instance attribute).
And indeed, if you have a urlsafe key (e.g. 'agFfcg4LEghFbXBsb3llZRgDDA') the way to turn it into a Key object is ndb.Key(urlsafe='agFfcg4LEghFbXBsb3llZRgDDA').
Good luck!

If cid is your entity then you could do that:
from google.appengine.ext import ndb
cme_only = ndb.Key(Comput, cid.key.id()).get()
But this will return you basically the same entity that you start with, the cid, But in general this is one way of querying by key.
You can check more on how to construct keys in the docs.

Related

AppEngine - Search ndb by key inequality

How can one search for ndb models based on key inequality?
For example, for a string one can use:
def add_inequality_filter(query, attr, given)
end = given + u'\ufffd'
return query.filter(attr >= given, attr < end)
add_inequality_filter(query, "key", "abc.")
If key were an ordinary string property this would work, however the key is a ModelKey.
Comparing the key (or _key) to a string triggers a BadValueError.
There does not appear to be a documented way to create a ModelKey (or equivalent) for comparison.
When I try to filter on __key__ > (the db way) I get a Cannot filter a non-Node argument.
The db to ndb documentation certainly indicates that this should be possible.
To answer my own question, the given and end in this need to be ndb.Key instances, whereas I had only attempted ModelKey, KeyProperty and strings.

Composite or FilterPredicate query on Ref'd entity

Here's what I have:
class A{
Ref<foo> b;
Ref<foo> c;
int code;
Date timestamp
}
The pseudo "where" clause of the SQL statement would like like this:
where b = object or (c = object and code = 1) order by timestamp
In plain English, give me all the records of A if b equals the specific object or if c equals the specified object when code equals 1. Order the result w/ timestamp.
Is the composite query part even possible w/ datastore (Objectify)? I really don't want to do two queries and merge the results, because I have to sort by timestamp.
Any help is appreciated.
P.S. I already tried
new FilterPredicate(b, EQUAL, object)
This didn't work, because the entity type is not a support type.
Thanks!
Pass a native datastore Key object to the FilterPredicate. The Google SDK Key, not the generic Objectify Key<?>.
Normally when filtering on properties, Objectify translates Ref<?> and Key<?> objects to native datastore keys for you. With the google-supplied FilterPredicate, that isn't an option. So you have to do the translation manually.
Objectify stores all Key<?> and Ref<?> fields and native datastore Keys, so you can freely interchange them (or even change the type of fields if you want).

ndb retrieving entity key by ID without parent

I want to get an entity key knowing entity ID and an ancestor.
ID is unique within entity group defined by the ancestor.
It seems to me that it's not possible using ndb interface. As I understand datastore it may be caused by the fact that this operation requires full index scan to perform.
The workaround I used is to create a computed property in the model, which will contain the id part of the key. I'm able now to do an ancestor query and get the key
class SomeModel(ndb.Model):
ID = ndb.ComputedProperty( lambda self: self.key.id() )
#classmethod
def id_to_key(cls, identifier, ancestor):
return cls.query(cls.ID == identifier,
ancestor = ancestor.key ).get( keys_only = True)
It seems to work, but are there any better solutions to this problem?
Update
It seems that for datastore the natural solution is to use full paths instead of identifiers. Initially I thought it'd be too burdensome. After reading dragonx answer I redesigned my application. To my suprise everything looks much simpler now. Additional benefits are that my entities will use less space and I won't need additional indexes.
I ran into this problem too. I think you do have the solution.
The better solution would be to stop using IDs to reference entities, and store either the actual key or a full path.
Internally, I use keys instead of IDs.
On my rest API, I used to do http://url/kind/id (where id looked like "123") to fetch an entity. I modified that to provide the complete ancestor path to the entity: http://url/kind/ancestor-ancestor-id (789-456-123), I'd then parse that string, generate a key, and then get by key.
Since you have full information about your ancestor and you know your id, you could directly create your key and get the entity, as follows:
my_key = ndb.Key(Ancestor, ancestor.key.id(), SomeModel, id)
entity = my_key.get()
This way you avoid making a query that costs more than a get operation both in terms of money and speed.
Hope this helps.
I want to make a little addition to dargonx's answer.
In my application on front-end I use string representation of keys:
str(instance.key())
When I need to make some changes with instence even if it is a descendant I use only string representation of its key. For example I have key_str -- argument from request to delete instance':
instance = Kind.get(key_str)
instance.delete()
My solution is using urlsafe to get item without worry about parent id:
pk = ndb.Key(Product, 1234)
usafe = LocationItem.get_by_id(5678, parent=pk).key.urlsafe()
# now can get by urlsafe
item = ndb.Key(urlsafe=usafe)
print item

NDB projection & caching questions

I have a couple of doubts regarding how NDB projection queries work and how the caching behaves behind the scenes
So given a model similar to:
class Users(ndb.Model):
user_name = ndb.StringProperty(required=True)
user_email = ndb.StringProperty(required=True)
user_password = ndb.StringProperty(required=True)
#classmethod # THIS ONE DOES NOT WORK
def get_profile_info(cls, id):
return ndb.Key(Users, id).get(projection=[Users.user_name])
#classmethod # THIS ONE WORKS
def get_profile_info(cls, id):
return Users.query(Users.key == ndb.Key(Users, id)).get(projection=[Users.user_name])
Why does the first classmethod raise a "TypeError: Unknown configuration option ('projection')"? Can't I simply call a projection on a direct get of a key, instead of having to query for a key?
Secondly, regarding caching, I'm not sure if I correctly understood this thread: NDB Caching When Using Projected Queries
Aren't projected queries cached? Does this mean its better to simply call a get() (and fetch the whole instance) so it is cached, instead of projecting?
Thanks in advance!
As per the error a projection makes no sense when using get. From the docs " It only gets values for those properties in the projection. It gets this data from the query index (and thus, properties in the projection must be indexed)". So doing get isn't accessing the object properties via indexes. Note gvr's comment on caching in your referenced question.

How to check the Text is null or not using JDO

I write these codes
Query q = pm.newQuery(User.class);
q.setFilter("textPosts != null"); // textPosts is a Text
List<User> users = (List<User>) q.execute();
resp.getWriter().println("user num: " + users.size());
And I get
user num: 0
I'm sure that the number should greater than 0.
I probably miss something important.
Thanks in advance!
Querying Unindexed properties:
A query with a filter or sort order on a property will never match an entity with that property unindexed
So your entity is not found because Text properties are never indexed.
This is also relevant (but in your case Text being unindexed prevails) - entities with non-existing properties are not found with queries:
The App Engine datastore distinguishes between an entity without a given property and an entity with a null value for a property. JDO does not support this distinction: every field of an object has a value, possibly null.
So if you have an Entity without a property, then it will not be found with a query, since a query requires that the property exists.
Maybe because Text will not be indexed for query purposes, as it specified in javadoc: http://code.google.com/intl/en/appengine/docs/java/javadoc/com/google/appengine/api/datastore/Text.html
Btw, i'm sure that it must throw exception at this case.

Resources