App Engine数据存储区查询结果随机返回

时间:2015-03-31 17:44:09

标签: google-app-engine servlets google-cloud-datastore

为了更好地理解数据存储的工作原理,我在项目的HttpServlet类中创建了一个包含多个实体和相关属性的数据存储区。 在创建并填充数据存储区之后,我立即查询它以便将Json对象返回给客户端,以便它可以动态更新其UI。

它有效,但我遇到了一个问题:在我第一次查询数据存储区后,我总是收到不同的排序结果,通常是相同项目的重复项。

这是我的HttpServlet代码:

public class MyServlet extends HttpServlet {
    ArrayList<Tour> m_tours = new ArrayList<Tour>();
    Key tourKey;
    DatastoreService datastore;
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
        //nothing special here
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        populateDatastore();

        String asyncMessage = req.getParameter("order");
        if(asyncMessage.equals("tours")){
            m_tours = getTours();
        }
        if(asyncMessage.equals("selectTour")){

        }

        Tours tours = new Tours(m_tours);
        resp.setContentType("application/json");
        PrintWriter out = resp.getWriter();
        out.print(new Gson().toJson(tours));
        out.flush();
    }
    private DatastoreService populateDatastore(){

    datastore = DatastoreServiceFactory.getDatastoreService();
    tourKey = KeyFactory.createKey("availabletours", "tours"); //parent

    Entity tour = new Entity("tour", tourKey);
    tour.setProperty("tourname", "Tour0");
    tour.setProperty("tourinfo", "info0");
    datastore.put(tour);

    Entity tour1 = new Entity("tour1", tourKey);
    tour1.setProperty("tourname", "Tour 1");
    tour1.setProperty("tourinfo", "info 1");
    datastore.put(tour1);

    //..... and so on

    return datastore;
}

private ArrayList<Tour> getTours(){
    ArrayList<Tour> toursArray = new ArrayList<Tour>();

    Query query = new Query(tourKey);
    List<Entity> tourss = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(9));
    for (Entity t : tourss) {
        String tourname=t.getProperty("tourname").toString();
        String tourinfo=t.getProperty("tourinfo").toString();
        Tour ts = new Tour(tourname,tourinfo);
        toursArray.add(ts);
    }

    return toursArray;
    }
}

我做错了什么?管理数据存储区的最佳方法是什么?

*编辑*

  

按照@Jeff Deskins的建议,将Entity对象统一到同一类型并设置祖先查询之后:

    datastore = DatastoreServiceFactory.getDatastoreService();
    tourKey = KeyFactory.createKey("availabletours", "tours"); //parent

    Entity tour = new Entity("tour", tourKey);
    tour.setProperty("tourname", "Tour0");
    tour.setProperty("tourinfo", "info0");
    datastore.put(tour);

    Entity tour1 = new Entity("tour", tourKey);
    tour1.setProperty("tourname", "Tour 1");
    tour1.setProperty("tourinfo", "info 1");
    datastore.put(tour1);

    //... ...  same way with the others
  

我设置了一个祖先查询:

    Query query = new Query("tour").setAncestor(tourKey);
    List<Entity> tourss = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(9));
    for (Entity t : tourss) {
        String tourname=t.getProperty("tourname").toString();
        String tourinfo=t.getProperty("tourinfo").toString();
        Tour ts = new Tour(tourname,tourinfo);
        toursArray.add(ts);
    }

这是我得到的结果:

第一次:{​​{0}}第二次:first query

  

编辑2:答案 -   除了执行祖先查询之外,我还需要对查询应用排序。因此,解决方案是为每个实体添加属性:

  Entity tour = new Entity("tour", tourKey);
        tour.setProperty("tourname", "Tour 1");
        tour.setProperty("tourinfo", "info 1");
        tour.setProperty("order","0");
  Entity tour = new Entity("tour", tourKey);
        tour.setProperty("tourname", "Tour 2");
        tour.setProperty("tourinfo", "info 2");
        tour.setProperty("order","1");

然后对查询应用排序过滤器:

    ArrayList<Tour> toursArray = new ArrayList<Tour>();

    Query query = new Query("tour").setAncestor(tourKey).addSort("order");
    List<Entity> tourss = new ArrayList<Entity>();
    tourss = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());

    for (Entity t : tourss) {
        String tourname=t.getProperty("tourname").toString();
        String tourinfo=t.getProperty("tourinfo").toString();
        Tour ts = new Tour(tourname,tourinfo);
        toursArray.add(ts);
    }

现在结果正确排序

1 个答案:

答案 0 :(得分:1)

如果实体对象的类型相同,则它们应遵循相同的模式。

使用相同的父键创建相同类型的不同实体:

Entity tour1 = new Entity("Tour", tourKey);
Entity tour2 = new Entity("Tour", tourKey);

在将上述对象填充并保存到数据存储区后,您可以通过以下方式进行查询:

Query tourQuery = new Query("Tour")
                         .setAncestor(tourKey);

祖先查询提供了强大的一致性。 https://cloud.google.com/appengine/docs/java/datastore/queries#Java_Ancestor_queries