Query Examples

See the following examples of various queries:

Querying all KiiObjects in a bucket

Let us start with the simplest example: querying all KiiObjects in a bucket.

  • // Create a query that returns all KiiObjects.
    KiiQuery all_query = new KiiQuery();
    
    try {
     // Query KiiObjects.
      KiiQueryResult<KiiObject> result = Kii.bucket("AppBucket")
              .query(all_query);
      // Alternatively, you can use:
      // KiiQueryResult<KiiObject> result = Kii.bucket("AppBucket")
      //         .query(null);
    
      List<KiiObject> objLists = result.getResult();
      for (KiiObject obj : objLists) {
        // Do something with KiiObjects in the result.
      }
    } catch (IOException e) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    }
  • // Create a query that returns all KiiObjects.
    KiiQuery all_query = new KiiQuery();
    
    // Query KiiObjects.
    Kii.bucket("AppBucket")
      .query(new KiiQueryCallBack<KiiObject>() {
      @Override
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        List<KiiObject> objLists = result.getResult();
        for (KiiObject obj : objLists) {
          // Do something with KiiObjects in the result.
        }
      }
    }, all_query);
    // Alternatively, you can use:
    // Kii.bucket("AppBucket")
    //         .query(..., null);

Here is what is happening in the sample code:

  • Creates a KiiQuery instance without a KiiClause instance. This query will get all KiiObjects.
  • Queries KiiObjects by calling the query() method in the target bucket by passing the query instance. Alternatively, you can call the method with a value of null.
  • Parses the query results returned as a KiiQueryResult instance by calling the getResult() method.

Executing an "all" query in a bucket will return all KiiObjects in it.

If you cannot get the expected result, check if you are querying the bucket in the correct scope (See here for more discussion).

Querying with multiple conditions

Next, let's query KiiObjects with the following conditions:

  • The field "gender" has a value of "Female".
  • The field "age" has a value greater than 18.
  • Sort the query results in ascending order by the field "age".
  • Limit the number of query results returned per call to 10.
  • // Prepare the target bucket to be queried.
    KiiBucket bucket = Kii.bucket("AppBucket");
    
    // Create a query with clauses.
    KiiQuery query = new KiiQuery(KiiClause.and(
            KiiClause.equals("gender", "Female"),
            KiiClause.greaterThan("age", 18)));
    
    // Define how to output the query result.
    query.sortByAsc("age");
    query.setLimit(10);
    
    try {
      // Query KiiObjects.
      KiiQueryResult<KiiObject> result = bucket.query(query);
      List<KiiObject> objLists = result.getResult();
      for (KiiObject obj : objLists) {
        // Do something with the first 10 KiiObjects.
      }
    
      // If there is more data to retrieve
      while (result.hasNext()) {
        // Query the next 10 KiiObjects with pagination.
        result = result.getNextQueryResult();
        objLists = result.getResult();
        for (KiiObject obj : objLists) {
          // Do something with the next 10 KiiObjects.
        }
      }
    } catch (IOException e) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    }
  • // Prepare the target bucket to be queried.
    KiiBucket bucket = Kii.bucket("AppBucket");
    
    // Create a query with clauses.
    KiiQuery query = new KiiQuery(KiiClause.and(
            KiiClause.equals("gender", "Female"),
            KiiClause.greaterThan("age", 18)));
    
    // Define how to output the query result.
    query.sortByAsc("age");
    query.setLimit(10);
    
    // Query KiiObjects.
    bucket.query(new KiiQueryCallBack<KiiObject>() {
      @Override
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        List<KiiObject> objLists = result.getResult();
        for (KiiObject obj : objLists) {
          // Do something with the first 10 KiiObjects.
        }
    
        // If there is more data to retrieve
        if (!result.hasNext()) {
          return;
        }
        // Query the next 10 KiiObjects with pagination.
        result.getNextQueryResult(this);
      }
    }, query);

Here is what is happening in the sample code:

  • Creates query conditions by calling the equals() and greaterThan() methods. Then creates a KiiClause instance by concatenating these two conditions with the and() method. Finally, the code creates a KiiQuery instance with this KiiClause instance.
  • Calls the sortByAsc() method of the KiiQuery instance to define the sort order.
  • Calls the setLimit() method of the KiiQuery instance to define the maximum number of KiiObjects returned in each query result set.
  • Queries KiiObjects by calling the query() method in the target bucket by passing the query instance.
  • Parses the query results returned as a KiiQueryResult instance by calling the getResult() method.

In this example, query results are parsed in consideration of pagination:

  • After parsing through the query results, the hasNext() method of the KiiQueryResult checks if more KiiObjects are available.
  • If there are more KiiObjects, the getNextQueryResult() method gets a new KiiQueryResult instance that contains the next 10 KiiObjects.

Querying with geolocation data

Let us now see how to query using geolocation data as a query condition.

Suppose that a KiiObject has a field named "location" whose value is a GeoPoint object as shown in the following sample code:

  • KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    // Create a KiiObject.
    KiiObject object = bucket.object();
    GeoPoint point = new GeoPoint(35.661561, 139.769595);
    object.set("location", point);
    try {
      // Save the KiiObject.
      object.save();
    } catch (IOException ioe) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    }
  • KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    // Create a KiiObject.
    KiiObject object = bucket.object();
    GeoPoint point = new GeoPoint(35.677379, 139.702148);
    object.set("location", point);
    
    // Save the KiiObject.
    object.save(new KiiObjectCallBack() {
      @Override
      public void onSaveCompleted(int token, KiiObject object, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
      }
    });

Here is an example that queries KiiObjects within a rectangle area using a GeoBox() clause.

  • // Prepare the target bucket to be queried.
    KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    try {
      // Define a GeoBox clause with northeast and southwest points.
      GeoPoint sw = new GeoPoint(35.52105, 139.699402);
      GeoPoint ne = new GeoPoint(36.069082, 140.07843);
      KiiClause clause = KiiClause.geoBox("location", ne, sw);
    
      // Create a query with the GeoBox clause.
      KiiQuery query = new KiiQuery(clause);
    
      // Query KiiObjects.
      KiiQueryResult<KiiObject> result = bucket.query(query);
    
      // Do something with the result.
    
    } catch (IOException ioe) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    }
  • // Prepare the target bucket to be queried.
    KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    // Define a GeoBox clause with northeast and southwest points.
    GeoPoint sw = new GeoPoint(35.52105, 139.699402);
    GeoPoint ne = new GeoPoint(36.069082, 140.07843);
    KiiClause clause = KiiClause.geoBox("location", ne, sw);
    
    // Create a query with the GeoBox clause.
    KiiQuery query = new KiiQuery(clause);
    
    // Query KiiObjects.
    bucket.query(new KiiQueryCallBack<KiiObject>() {
      @Override
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        // Do something with the result.
      }
    }, query);

As shown in the sample code, you define a GeoBox() clause by calling the geoBox() method with two GeoPoints, one representing the northeast point, and another one representing the southwest point.

Here is an example of querying KiiObjects within a circular area using a GeoDistance() clause. In this example, we will query KiiObjects that are in the area overlapped by two GeoDistances (GeoDistance1 and GeoDistance2). We will also sort query results in ascending order by the distance from GeoDistance1's center point.

  • // Prepare the target bucket to be queried.
    KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    try {
      // Define the first GeoDistance clause.
      String distanceField1 = "distance_from_center1";
      GeoPoint center1 = new GeoPoint(35.658603, 139.745433);
      KiiClause clause1 = KiiClause.geoDistance("location", center1,
              3000, distanceField1);
    
      // Define the second GeoDistance clause.
      GeoPoint center2 = new GeoPoint(35.681382, 139.766084);
      KiiClause clause2 = KiiClause.geoDistance("location", center2, 3000, null);
    
      // Create a query with the GeoDistance clauses and set the sort order.
      KiiQuery query = new KiiQuery(KiiClause.and(clause1, clause2));
      String sortKey = "_calculated." + distanceField1;
      query.sortByAsc(sortKey);
    
      // Query KiiObjects.
      KiiQueryResult<KiiObject> result = bucket.query(query);
    
      // Do something with the result.
      // This example just fetches the first KiiObject.
      List<KiiObject> objects = result.getResult();
      KiiObject objInquired = objects.get(0);
    
      // Get the distance from the center to the location.
      double distance = objInquired.getJSONObject("_calculated")
            .getDouble(distanceField1);
    } catch (IOException ioe) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    } catch (JSONException jse) {
      // Handle the error.
    }
  • // Prepare the target bucket to be queried.
    KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    // Define the first GeoDistance clause.
    final String distanceField1 = "distance_from_center1";
    GeoPoint center1 = new GeoPoint(35.658603, 139.745433);
    KiiClause clause1 = KiiClause.geoDistance("location", center1,
            3000, distanceField1);
    
    // Define the second GeoDistance clause.
    GeoPoint center2 = new GeoPoint(35.681382, 139.766084);
    KiiClause clause2 = KiiClause.geoDistance("location", center2, 3000, null);
    
    // Create a query with the GeoDistance clauses and set the sort order.
    KiiQuery query = new KiiQuery(KiiClause.and(clause1, clause2));
    String sortKey = "_calculated." + distanceField1;
    query.sortByAsc(sortKey);
    
    // Query KiiObjects.
    bucket.query(new KiiQueryCallBack<KiiObject>() {
      @Override
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        // Do something with the result.
        // This example just fetches the first KiiObject.
        List<KiiObject> objects = result.getResult();
        KiiObject objInquired = objects.get(0);
    
        try {
          // Get the distance from the center to the location.
          double distance = objInquired.getJSONObject("_calculated")
                  .getDouble(distanceField1);
        } catch (JSONException jse) {
          // Handle the error.
        }
      }
    }, query);

Here is what is happening in the sample code:

  • Defines two GeoDistance query conditions by calling the geoDistance() method. Here we specify a GeoPoint representing the center, a radius in meters, and optionally a field that stores the distance between the center of the circular area and a returned KiiObject. Kii Cloud will use this field in a query response.
  • Creates a KiiClause instance by concatenating two GeoDistance query conditions via the and() method. Then creates a KiiQuery instance using this KiiClause instance.
  • Calls the sortByAsc() method of the KiiQuery instance to set the sort order.
  • Queries KiiObjects by calling the query() method of the target bucket by passing the query instance.
  • Parses the query results by calling the getResult() method of the KiiQueryResult instance.

With a GeoDistance query condition, Kii Cloud can return the distance between the center point of a GeoPoint and each returned KiiObject. In this example, the distance between GeoDistance1's center point and KiiObjects are returned.

  • The distance will be stored in the field specified when the geoDistance() method is called (the "distance_from_center1" field in this example).
  • To sort query results by distance, call the sortByAsc() method with a string "_calculated." followed by the name of the distance field.
  • To get the distance, get the value (JSONObject) of the "_calculated" field by calling the getJSONObject() method, and then call the getDouble() method of the distance field.

Querying with predefined keys

Now, let us show an example of querying with predefined keys.

The next sample code gets KiiObjects that are owned by the current user and are either not updated after creation or updated within a day.

  • // Prepare the target bucket to be queried.
    KiiBucket bucket = Kii.bucket("AppBucket");
    
    // Get values to use in query conditions.
    String userId = KiiUser.getCurrentUser().toUri().getLastPathSegment();
    long withinOneDay = System.currentTimeMillis() - 24 * 60 * 60 * 1000;
    
    // Create a query with clauses using predefined keys and the retrieved values.
    KiiQuery query = new KiiQuery(KiiClause.and(
        KiiClause.equals("_owner", userId),
        KiiClause.or(
            KiiClause.equals("_version", 1),
            KiiClause.greaterThan("_created", withinOneDay))));
    
    // Define how to output the query result.
    query.sortByAsc("_created");
    query.setLimit(10);
    
    try {
      // Query KiiObjects.
      KiiQueryResult<KiiObject> result = bucket.query(query);
      List<KiiObject> objLists = result.getResult();
      for (KiiObject obj : objLists) {
        // Do something with the first 10 KiiObjects.
      }
    } catch (IOException e) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    }
  • // Prepare the target bucket to be queried.
    KiiBucket bucket = Kii.bucket("AppBucket");
    
    // Get values to use in query conditions.
    String userId = KiiUser.getCurrentUser().getID();
    long withinOneDay = System.currentTimeMillis() - 24 * 60 * 60 * 1000;
    
    // Create a query with clauses using predefined keys and the retrieved values.
    KiiQuery query = new KiiQuery(KiiClause.and(
        KiiClause.equals("_owner", userId),
        KiiClause.or(
            KiiClause.equals("_version", 1),
            KiiClause.greaterThan("_created", withinOneDay))));
    
    // Define how to output the query result.
    query.sortByAsc("_created");
    query.setLimit(10);
    
    // Query KiiObjects.
    bucket.query(new KiiQueryCallBack<KiiObject>() {
      @Override
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        List<KiiObject> objLists = result.getResult();
        for (KiiObject obj : objLists) {
          // Do something with the first 10 KiiObjects.
        }
      }
    }, query);

Querying with a specific field name and a field type

Now, let us show an example of querying with a specific field name and a field type. KiiObjects can have various custom fields that are not always consistent. By using a hasField() clause, we can narrow the results to KiiObjects that have a specific field of a specific data type.

The next sample code gets KiiObjects that have an optional promotionalCode field.

  • // Create a query with a clause using a specific field and a type.
    KiiQuery hasField_query = new KiiQuery(KiiClause.hasField("promotionalCode",FieldType.String));
    
    try {
      // Query KiiObjects.
      KiiQueryResult<KiiObject> result = Kii.bucket("AppBucket")
              .query(hasField_query);
    
      List<KiiObject> objLists = result.getResult();
      for (KiiObject obj : objLists) {
        // Do something with KiiObjects in the result.
      }
    } catch (IOException e) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    }
  • // Create a query with a clause using a specific field and a type.
    KiiQuery hasField_query = new KiiQuery(KiiClause.hasField("promotionalCode",FieldType.String));
    
    // Query KiiObjects.
    Kii.bucket("AppBucket")
      .query(new KiiQueryCallBack<KiiObject>() {
      @Override
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        List<KiiObject> objLists = result.getResult();
        for (KiiObject obj : objLists) {
          // Do something with KiiObjects in the result.
        }
      }
    }, hasField_query);

Querying with a not clause

Now, let us show an example of querying with a not() clause. This time, we will query KiiObjects that are outside a specified rectangle area.

  • // Prepare the target bucket to be queried.
    KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    try {
      // Define a GeoBox clause with northeast and southwest points.
      GeoPoint sw = new GeoPoint(35.52105, 139.699402);
      GeoPoint ne = new GeoPoint(36.069082, 140.07843);
      KiiClause geoBoxClause = KiiClause.GeoBox("location", ne, sw);
    
      // Define a not clause with the Geobox clause.
      KiiClause notInTheBoxClause = KiiClause.not(geoBoxClause)
    
      // Create a query with the Not clause.
      KiiQuery query = new KiiQuery(notInTheBoxClause);
    
      // Query KiiObjects.
      KiiQueryResult<KiiObject> result = bucket.query(query);
    
      // Do something with the result.
    
    } catch (IOException ioe) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    }
  • // Prepare the target bucket to be queried.
    KiiBucket bucket = KiiUser.getCurrentUser().bucket("myBucket");
    
    // Define a GeoBox clause with northeast and southwest points.
    GeoPoint sw = new GeoPoint(35.52105, 139.699402);
    GeoPoint ne = new GeoPoint(36.069082, 140.07843);
    KiiClause geoBoxClause = KiiClause.GeoBox("location", ne, sw);
    
    // Define a not clause with the Geobox clause.
    KiiClause notInTheBoxClause = KiiClause.not(geoBoxClause)
    
    // Create a query with the Not clause.
    KiiQuery query = new KiiQuery(notInTheBoxClause);
    
    // Query KiiObjects.
    bucket.query(new KiiQueryCallBack<KiiObject>() {
      @Override
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        // Do something with the result.
      }
    }, query);

Querying with a not() clause can decrease performance but you might be able to transform the clause to avoid a not operator. See Transforming a not clause for more information.