Convert string to NDB query - google-app-engine

If I have a class like:
class carModel(ndb.Model):
type = ndb.StringProperty(required=True)
brand = ndb.StringProperty(required=True)
I want that a user can type a GQL query into a text field. (Same like at the Datastore viewer).
I'll get the string and insert it into my query - for example:
queryString = "carModel.brand=='bmw'"
qry = carModel.query(queryString)
result = query.get()
I get following error message:
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/query.py", line 1059, in filter
raise TypeError('Cannot filter a non-Node argument; received %r' % arg)
TypeError: Cannot filter a non-Node argument; received "carModel.brand=='bmw'"
I think that class has not been recognized from the string. Any suggestions for a solution where I can keep the users freedom to use any GQL queries on the model?

carModel.brand is actually a class and property reference not a string.
Either construct the query using GQL, or you have to assemble the query as per the Query class docs which means parsing your own set of arguments.
Be sure to use appropriate substitution rules or someone could query for things not intended and check for GQL that does not comply with what ever rules you have in place, or someone can query for anything. Remember also that indexes must exist for the queries submitted.

Related

How to get result based on specific keywords using Google App Engine NO-SQL datastore query in java?

We use GoogleInfo table, in that table, we store scopes of application. e.g."https://www.googleapis.com/auth/drive.appdata,https://www.googleapis.com/auth/drive.file"
and I am trying to get a result based on some keyword like "drive" from scopes, based on that keyword I am trying to get a result. following is my code. Please suggest.
String keywords[] = {"admin","drive","gmail","userinfo"};
Query query = pm.newQuery("SELECT scopes FROM com.cloudcodes.gcontrol.dataaccesslayer.insights.google.drive.GoogleInfo where :p.contains(scopes)");
result = (List) query.execute(Arrays.asList(keywords));
List tempResult = new ArrayList();
tempResult.addAll(result);
return tempResult;
Seems that you are using JDO [1] and the PersistanceManager [2].
As far as I can see the query you are trying to execute might be wrong. Check how to perform queries with JDO [3].
Your query is:
String keywords[] = {"admin","drive","gmail","userinfo"};
Query query = pm.newQuery("SELECT scopes FROM com.cloudcodes.gcontrol.dataaccesslayer.insights.google.drive.GoogleInfo where :p.contains(scopes)");
result = (List) query.execute(Arrays.asList(keywords));
Looks like you want to do something like:
//Query for all persons with lastName equal to Smith or Jones
Query q = pm.newQuery(Person.class, ":p.contains(lastName)");
q.execute(Arrays.asList("Smith", "Jones"));
Person.class is the kind
Arrays.asList("Smith", "Jones")
This parameter ":p.contains(lastName)" that defines lastName is the property we want to check on.
You are setting the class as com.cloudcodes.gcontrol.dataaccesslayer.insights.google.drive.GoogleInfo, I suppose that this is the full Java name package where the class habits, and the class name is GoogleInfo. So you could try:
Query q = pm.newQuery(GoogleInfo.class, ":p.contains(scopes)");
q.execute(Arrays.asList("admin","drive","gmail","userinfo"));
You want to retrieve scopes. I assume that you want to use the REST API. So inside :p.contains(“scopes”) might go another property related to your keyWords that is in the Entity you want to retrieve, maybe an array property?
Here I share with you some docs that might be useful [4][5].
Hope this helps!
[1] https://cloud.google.com/appengine/docs/standard/java/datastore/jdo/overview-dn2
[2] http://massapi.com/method/javax/jdo/PersistenceManager.newQuery-4.html
[3] https://cloud.google.com/appengine/docs/standard/java/datastore/jdo/queries
[4] https://cloud.google.com/datastore/docs/concepts/overview#comparison_with_traditional_databases
[5] https://cloud.google.com/datastore/docs/reference/gql_reference

Can't execute a distinct projection query

I have a simple little "Observation" class:
from google.appengine.ext import ndb
class Observation(ndb.Model):
remote_id = ndb.StringProperty()
dimension_id = ndb.IntegerProperty()
metric = ndb.StringProperty()
timestamp_observed = ndb.StringProperty()
timestamp_received = ndb.DateTimeProperty(auto_now_add=True)
#classmethod
def query_book(cls):
return cls.query()
I can run projection queries against the Datastore to return only certain columns. E.g:
observations = Observation.query().fetch(projection=[Observation.dimension_id])
This works nicely, but I only want unique results. The documentation makes this sound easy:
# Functionally equivalent
Article.query(projection=[Article.author], group_by=[Article.author])
Article.query(projection=[Article.author], distinct=True)
But when I do this:
observations = Observation.query().fetch(projection=[Observation.dimension_id], group_by=[Observation.dimension_id])
observations = Observation.query().fetch(projection=[Observation.dimension_id], distinct=True)
I get errors for both variants.
TypeError: Unknown configuration option ('group_by')
TypeError: Unknown configuration option ('distinct')
This happens on localhost and in the prod environment too. What am I missing?
Silly me - all of these params need to sit within the query() function, not within fetch(). The projection elements actually works in fetch(), but you need to move both the projection and distinct arguments into query() to get it to work.
From Grouping:
Projection queries can use the distinct keyword to ensure that only
completely unique results will be returned in a result set. This will
only return the first result for entities which have the same values
for the properties that are being projected.
Article.query(projection=[Article.author], group_by=[Article.author])
Article.query(projection=[Article.author], distinct=True)
Both queries are equivalent and will produce each author's name only
once.
Hope this helps anyone else with a similar problem :)

Google app engine: ndb sort property

I have the following model:
class Product(ndb.Model):
name = ndb.StringProperty()
bidTime = ndb.DateTimeProperty()
price = ndb.IntegerProperty()
...
I'd likd to use the following query:
productRanks = Product.query(Product.bidTime>=startDate,
Product.bidTime<endDate).order(-Product.price).fetch()
where startDate and endDate are datetime objects. But I got the following error message:
The first sort property must be the same as the property to which the inequality filter is applied
If I add Product.bidTime in the order then there will be no error:
.order(Product.bidTime, -Product.price)
However, the sorted result would be wrong (according to date, not price). So, what is the problem?
There is no problem as far as appengine is concerned. It is behaving as documented. From the docs
Note: Because of the way the App Engine Datastore executes queries, if
a query specifies inequality filters on a property and sort orders on
other properties, the property used in the inequality filters must be
ordered before the other properties.
See https://developers.google.com/appengine/docs/python/datastore/queries#Sort_Orders
You may need to sort in memory after you get your result set.

How do Django queries 'cast' argument strings into the appropriate field-matching types?

Let's take the Django tutorial. In the first part we can find this model:
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
with which Django generates the following SQL:
CREATE TABLE "polls_poll" (
"id" serial NOT NULL PRIMARY KEY,
"question" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
One can note that Django automatically added an AutoField, gloriously named id, which is akin to an IntegerField in that it handles integers.
On part 3, we build a custom view, reachable through the following url pattern:
(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
The tutorial helpfully explains that a subsequent HTTP request will result in the following call:
detail(request=<HttpRequest object>, poll_id='23')
A few scrolls later, we can find this snippet:
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)
Notice how the URL tail component becomes the poll_id argument with a string value of '23', happily churned by the Manager (and therefore QuerySet) get method to produce the result of an SQL query containing a WHERE clause with an integer value of 23 certainly looking like that one:
SELECT * FROM polls_poll WHERE id=23
Certainly Django performed the conversion from the fact that the id field is an AutoField one. The question is how, and when. Specifically, I want to know which internal methods are called, and in what order (kind of like what the doc explains for form validation).
Note: I took a look at sources in django.db.models and found a few *prep* methods, but don't know neither when or where they are called, let alone if they're what I'm looking for.
PS: I know it's not casting stricto sensu, but I think you get the idea.
I think it's in django.db.models.query.get_where_clause

GQL query with numeric id in datastore viewer

I want to build GQL query to get an object using its numeric id. I'm doing this in Datastore viewer in App management console, so I can't use Model.get_by_id(numeric_id). Something like
SELECT * FROM Model WHERE id = <numeric_id>
also doesn't work.
Try this:
SELECT * FROM Model where __key__ = KEY('Model', <numeric_id>)
Unfortunately, there does not appear to be a way to write a query equivalent to
SELECT * FROM Model WHERE id = <numeric_id>
which would select all Model entities with the given id. If you're ok with something equivalent to
SELECT * FROM Model WHERE id = <numeric_id> AND parent IS NULL
you can use something like
SELECT * FROM Model where __key__ = KEY('Model', <numeric_id>)
If your entity does have a parent though, you'll need to specify that as part of the key, like
SELECT * FROM Model where __key__ = KEY('ParentModel', <parent_name_or_id>, 'Model', <numeric_id>)
If the parent itself has a parent, you'll need to specify that too. (Grandparent goes left of the parent, and so on.)
Of course if you're not restricted to GQL (like if you're using Python, Go, or Java), you can query the keys, decode them and filter by id, then fetch the corresponding entities. But of course that doesn't work in the Datastore Viewer since you can only use GQL.
Another way around is, first get the key for the entity using the id by
key = db.Key.from_path('Model', int(id))
then get the object by
obj = db.get(key)
The advantage is, you do not have to do any string formatting.
reference: problem set 3 at this course, https://classroom.udacity.com/courses/cs253/
I was getting this error:
GQL Query error: Encountered ... at line 1, column 42. Was expecting
one of: UNQUOTED_NAME ... QUOTED_NAME ..."
It turns out that in the Google AppEngine datastore developer's admin console, you should drop the quotes and use something like this:
SELECT * FROM MyEntity WHERE __key__ = Key(MyEntity, 5695872079757312)
In my case I had to change the type of ID from String to Long

Resources