Fetching first record from NDB datastore in GAE
<p>I'm currently writing an application on the Google App Engine for Python. I want to fetch the first record in my datastore, but for some reason this won't work. This is how I'd do it in MySQL:</p>

<pre><code>SELECT * FROM MyClass LIMIT 1;
</code></pre>

<p>However since I'm new to NDB, I can't quite seem to wrap my head around how this works. I tried reading <a href="https://cloud.google.com/appengine/docs/python/ndb/queryclass" rel="nofollow">the documentation</a> for examples but they don't quite work.</p>

<p>This is the code I currently have:</p>

<pre><code>from google.appengine.ext.ndb import Model as NdbModel
from google.appengine.ext.ndb import StringProperty


class Model(NdbModel):

    @classmethod
    def get_first(cls):
        """
        Get the first record in the model datastore
        :return: Model
        """
        try:
            return cls.query().fetch(1)[0]
        except IndexError:
            raise ModelException("No records found in [%s] datastore" % cls.__name__)


class MyClass(Model):
    foo = StringProperty()
    bar = StringProperty()

a = MyClass.get_first() # TypeError: 'NoneType' object does not support item assignment
</code></pre>

<hr>

<p>This is my full stack trace:</p>

<pre><code>TypeError: 'NoneType' object does not support item assignment
    at _store_value (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py:1127)
    at _deserialize (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py:1496)
    at _from_pb (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py:3209)
    at pb_to_entity (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py:691)
    at pb_to_query_result (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py:201)
    at _process_results (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/datastore/datastore_query.py:2980)
    at __query_result_hook (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/datastore/datastore_query.py:2947)
    at get_result (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/apiproxy_stub_map.py:613)
    at _on_rpc_completion (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py:513)
    at _run_to_list (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/query.py:995)
    at _help_tasklet_along (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py:427)
    at get_result (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py:383)
    at fetch (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/query.py:1218)
    at positional_wrapper (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/utils.py:160)
    at get_first (/base/data/home/apps/s~project-id/v1.395271489319521947/project/core/models/utils.py:55)
    at me (/base/data/home/apps/s~project-id/v1.395271489319521947/project/core/routes/api/v1/profile.py:22)
    at dispatch_request (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:1625)
    at full_dispatch_request (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:1639)
    at handle_user_exception (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:1544)
    at full_dispatch_request (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:1641)
    at wsgi_app (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:1988)
    at handle_exception (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:1567)
    at wsgi_app (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:1991)
    at __call__ (/base/data/home/apps/s~project-id/v1.395271489319521947/lib/flask/app.py:2000)
    at Handle (/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py:267)
</code></pre>

<p>It seems like you are trying to retrieve the data immediately after it is written to the Datastore which will not work unless you set the same <code>parent key</code> on each entity as stated in App Engine's <a href="https://cloud.google.com/appengine/docs/python/getting-started/storing-data-datastore" rel="nofollow">Storing Data in Cloud Datastore</a> document.</p>

<p>To create a <code>parent key</code>, you could write:</p>

<pre><code>from google.appengine.ext.ndb import Key
parent_key = Key('my_data', 'version_1')
</code></pre>

<p>and when you create your entity you should pass the <code>parent key</code> to the <code>constructor</code>:</p>

<pre><code>my_entity = MyKindClass(parent=parent_key, foo=foo_input, bar=bar_input)
</code></pre>

<p>Then, you query your database by passing the <code>parent_key</code> to <code>query</code> method of your <code>kind</code> class:</p>

<pre><code>first_result = MyKindClass.query(
            ancestor=parent_key).order(-MyKindClass.created).get()
</code></pre>

<p>I think you are interested in getting the latest data, so I ordered the results using <code>order</code> method with <code>-</code> operator which orders data descendingly. In addition, I used <code>get</code> method instead of <code>fetch(1)</code> which returns the first query result or <code>None</code> if there is no data.</p>

<p>The full code will be:</p>

<pre><code>import webapp2
from google.appengine.ext.ndb import (
    Model, StringProperty, DateTimeProperty, Key)


class MyKindClass(Model):
    foo = StringProperty()
    bar = StringProperty()
    created = DateTimeProperty(auto_now_add=True)


parent_key = Key('my_data', 'version_1')


class MainHandler(webapp2.RequestHandler):

    def get(self):
        foo_input = self.request.get('foo')
        bar_input = self.request.get('bar')
        if foo_input and bar_input:
            my_entity = MyKindClass(parent=parent_key,
                                    foo=foo_input, bar=bar_input)
            my_entity.put()

        first_result = MyKindClass.query(
            ancestor=parent_key).order(-MyKindClass.created).get()
        if first_result is not None:
            self.response.write('foo: %s, and bar: %s' %
                                (first_result.foo, first_result.bar))
        else:
            self.response.write('No data yet!')

app = webapp2.WSGIApplication([
    ('/', MainHandler)
], debug=True)
</code></pre>

<p>For more information, see App Engine's <a href="https://cloud.google.com/appengine/docs/python/ndb/" rel="nofollow">The Python NDB Client Library Overview</a> document.</p>

python google-app-engine