0
votes

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 datastore 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 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"
    }
2

2 Answers

1
votes

Just wanted to add to konqi's answer based on comments:

If you are using Cloud Endpoints with Android Studio you must first switch to "project" view in your navigation panel, then navigate to your "backend" folder then src->main->webapp->WEB-INF and then in that folder you must manually create a datastore-indexes.xml file. Here is what yours would look like:

<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="true">
    <!-- NOTE: Not necessary to create composite indexes here for single property indices b.c. they are build in.-->

    <!-- If you do not specify direction, default is: direction="asc" -->

    <datastore-index kind="Attendance" ancestor="true" source="manual">
        <property name="date" direction="asc"/>
    </datastore-index>

</datastore-indexes>
1
votes

Answering Question 1:

Appengine uses UTC timestamps. Therefor your timestamp is converted from your time zone to UTC. It is still the same date and time though. During output you need to consider that the timestamp may contain the timezone and format / calculate the local time accordingly.

Answering Question 2:

You have all the information you need in your error. If you add

<datastore-index kind="Attendance" ancestor="true" source="manual">
    <property name="date" direction="asc"/>
</datastore-index>

to your datastore-indexes.xml your query should work. If the file doesn't exist yet, create it under src/main/webapp/WEB-INF/datastore-indexes.xml, next to your web.xml and appengine-web.xml files. You can find an example on this page.

As for why: The answer with this error is always: Because datastore requires a composite index for this query.