hiroshi
hiroshi

Reputation: 7251

GAE python ndb - How to get_by_id with projection?

I'd like to do this.

Content.get_by_id(content_id, projection=['title'])

However, I got an error.

TypeError: Unknown configuration option ('projection')

I should do like this. How?

Content.query(key=Key('Content', content_id)).get(projection=['title'])

Why bother projection for getting an entity? Because Content.body could be large so that I want to reduce db read time and instance hours.

Upvotes: 0

Views: 765

Answers (4)

yoonjesung
yoonjesung

Reputation: 1198

There is a simpler method than the currently posted answers.

As previous answers have mentioned, projections are only for ndb.Queries.

Previous answers suggest to use the entity returned by get_by_id to perform a projection query in the form of:

<Model>.query(<Model>.key == ndb.Key('<Model>', model_id).get(projection=['property_1', 'property_2', ...])

However, you can just manipulate the model's _properties directly. (See: https://cloud.google.com/appengine/docs/standard/python/ndb/modelclass#intro_properties)

For example:

desired_properties = ['title', 'tags']

content = Content.get_by_id(content_id)
content._properties = {k: v for k, v in content._properties.iteritems()
                       if k in desired_properties}
print content

This would update the entity properties and only return those properties whose keys are in the desired_properties list.

Not sure if this is the intended functionality behind _properties but it works, and it also prevents the need of generating/maintaining additional indexes for the projection queries.

The only down-side is that this retrieves the entire entity in-memory first. If the entity has arbitrarily large metadata properties that will affect performance, it would be a better idea to use the projection query instead.

Upvotes: 1

hiroshi
hiroshi

Reputation: 7251

I figured out that following code.

Content.query(Content.key == ndb.Key('Content', content_id)).get(projection=['etag'])

I found a hint from https://developers.google.com/appengine/docs/python/ndb/properties

Don't name a property "key." This name is reserved for a special property used to store the Model key. Though it may work locally, a property named "key" will prevent deployment to App Engine.

Upvotes: 1

marcadian
marcadian

Reputation: 2618

Projection is only for query, not get by id. You can put the content.body in a different db model and store only the ndb.Key of it in the Content.

Upvotes: 0

Sandeep
Sandeep

Reputation: 813

If you are using ndb, the below query should work

Content.query(key=Key('Content', content_id)).get(projection=[Content.title])

Note: It gets this data from the query index. So, make sure that index is enabled for the column. Reference https://developers.google.com/appengine/docs/python/ndb/queries#projection

Upvotes: 1

Related Questions