how to apply filter on ancestor query

529 views
Skip to first unread message

Baqir Rizvi

unread,
Jun 16, 2016, 3:07:57 AM6/16/16
to objectify-appengine
I have two entity model Student and attendance such that each attendance entity has associated student parent.

Attendance model:

@Entity
public class Attendance {

 
@Id
 
Long id;
 
@Index
 
Date date;
 
@Parent
 
@Index
 
@ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
 
Ref<Student> studentRef;

 
public Long getId() {
 
return id;
 
}

 
public Date getDate() {
 
return date;
 
}

 
public void setDate(Date date) {
 
this.date = date;
 
}
 
public String getWebsafeKey() {
 
return Key.create(studentRef.getKey(), Attendance.class, id).getString();
 
}
}



Student model:

@Entity
public class Student {
 
 
@Id
 
Long id;
 
@Index
 
String name;

 
String student_id;

 
Long mobile_number;
 
String email;

 
@Index
 
@ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
 
List<Ref<Shift>> shiftRef = new ArrayList<Ref<Shift>>();

 
public Long getId() {
 
return id;
 
}

 
public String getStudent_id() {
 
return student_id;
 
}

 
public void setStudent_id(String student_id) {
 
this.student_id = student_id;
 
}

 
public String getName() {
 
return name;
 
}

 
public void setName(String name) {
 
this.name = name;
 
}

 
public Long getMobile_number() {
 
return mobile_number;
 
}

 
public void setMobile_number(Long mobile_number) {
 
this.mobile_number = mobile_number;
 
}

 
public String getEmail() {
 
return email;
 
}

 
public void setEmail(String email) {
 
this.email = email;
 
}

 
public String getWebsafeKey() {
 
return Key.create(Student.class, id).getString();
 
}
}




This how I am inserting an attendance entity into datastore:

Key<Student> studentKey = Key.create(student_web_safe_key);
Date date = new Date();
date
.setTime(System.currentTimeMillis());
attendance
.setDate(date);
attendance
.studentRef = Ref.create(studentKey);
ofy
().save().entity(attendance).now();

Questions:

  1. The above query store the date in format: 2016-06-15 (18:01:18.845) IST     
But when I retrieve the same entity without specifying its parent then its gives me date as: "date ": "2016-06-15T12:31:18.845Z". please explain this?

2.  I am able to store attendance corresponds to each student and also able to retrieve all the attendance of a student.
but how can retrieve attendance of student on specified date or range of dates?
I tried blow query:
Query<Attendance> query = ofy().load().type(Attendance.class).ancestor(studentKey).filter("date =",date);

but it gives me following exception:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 503 Service Unavailable

{

  "code": 503,

  "errors": [

    {

      "domain": "global",

      "message": "com.google.appengine.api.datastore.DatastoreNeedIndexException: no matching index found. recommended index is:\n- kind: Attendance\n  ancestor: yes\n  properties:\n  - name: date\n\nThe suggested index for this query is:\n    <datastore-index kind=\"Attendance\" ancestor=\"true\" source=\"manual\">\n        <property name=\"date\" direction=\"asc\"/>\n    </datastore-index>\n\n",

      "reason": "backendError"

    }

  ],

  "message": "com.google.appengine.api.datastore.DatastoreNeedIndexException: no matching index found. recommended index is:\n- kind: Attendance\n  ancestor: yes\n  properties:\n  - name: date\n\nThe suggested index for this query is:\n    <datastore-index kind=\"Attendance\" ancestor=\"true\" source=\"manual\">\n        <property name=\"date\" direction=\"asc\"/>\n    </datastore-index>\n\n"

}

Nicholas Okunew

unread,
Jun 16, 2016, 3:23:47 AM6/16/16
to objectify...@googlegroups.com
All dates are stored in UTC in the datastore, that is why your date seems to have changed on write/read - note the z on the end, which indicates GMT+0000. This is just a timezone adjustment.

To query for a date on a particular day, you need to do a range query, such as

.filter("date >=",dateAtMidnight).filter("date <",  nextDateAtMidnight)

You will also require an index for this query, you can copy the specified index definition into your datastore-indexes.xml, but you'll need to understand this sooner or later, so read up.
In many circumstances it makes sense to denormalise data to make querying easier, so you may want to store a duplicate field which is a string representation of a date (excluding time and zone), and query for that instead (which allows you to get away with just @Index, and ignore timezones, times etc). This makes sense if this is a common query, or day based queries are very frequent, or typically the time/zone is irrelevant. Make sure to store the day in a format that lexicographically sorts, such as yyyy-MM-dd


--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appen...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Baqir Rizvi

unread,
Jun 16, 2016, 9:20:19 AM6/16/16
to objectify-appengine
Thanks for your reply Nick.
I am using your your 2nd way of duplicating field which is string representation of date in format YYYY-MM-DD.
now the problem is I am able to retrieve the entity by using following query:

Query<Attendance> query = ofy().load().type(Attendance.class).ancestor(studentKey).filter("string_date =",date);

But unable to do query based on less than or greater than(<> or <= or >=) on string_date which is in YYYY-MM-DD format. e.g
Query<Attendance> query = ofy().load().type(Attendance.class).ancestor(studentKey).filter("string_date >=",date);

gives me same exception as I post earlier.

Can You please tell me what I am doing wrong?

Moreover, I didnt find any file name datastore-index.xml in my project in android studio.

To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsub...@googlegroups.com.

Jeff Schnitzer

unread,
Jun 16, 2016, 11:47:16 AM6/16/16
to objectify-appengine
You’ll need to add a multiproperty index to your datastore-indexes.xml file. The exception message includes the literal text you need to add.


Also - I recommend ditching the native java time types and using joda time. It clears up a _lot_ of these issues. Objectify has builtin support, just run this:

JodaTimeTranslators.add(factory());

Now you can clearly distinguish between DateTime (the full instant, like Date) and LocalDate (‘YYYY-MM-DD’). You can also use LocalDateTime if you want to drop the timezone from an instant. Real world time handling is quite complicated and Joda allows you to express pretty much everything you need.

Jeff


To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appen...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appen...@googlegroups.com.

Baqir Rizvi

unread,
Jun 17, 2016, 5:22:51 AM6/17/16
to objectify-appengine, je...@infohazard.org
Thanks jeff, can you please tell me steps to use jodatime in objectify?
how do I insert a joda date and retrieve from datastore. 

Jeff Schnitzer

unread,
Jun 17, 2016, 10:09:42 AM6/17/16
to objectify-appengine
If you add this line before you register your entity classes:

JodaTimeTranslators.add(factory());

Then you can just use DateTime or LocalDate or whatnot as fields in your entity classes. Note that you need to register the translators first, otherwise Objectify won’t know what to do with them.

Jeff

On Fri, Jun 17, 2016 at 3:22 AM, Baqir Rizvi <baqir.g...@gmail.com> wrote:
Thanks jeff, can you please tell me steps to use jodatime in objectify?
how do I insert a joda date and retrieve from datastore. 

--
Reply all
Reply to author
Forward
0 new messages