# Querying the same fields for many different values on AppEngine

I'm creating a gradebook. Many students earn a grade in many standards each. I'm hoping to get help analyzing the code below for efficient use of asynchronous result fetching. ofy is an Objectify object, which is basically just a convenience wrapper over the async fetching capabilities of AppEngine.

public List<StandardScoreDAO> getStandardScores(
ArrayList<Long> studentIdLongs, ArrayList<Long> standardIdLongs)
{
ObjectifyService.register(StandardScoreDAO.class);
Objectify ofy = ObjectifyService.begin();

List<Iterator<StandardScoreDAO>> results = new ArrayList<Iterator<StandardScoreDAO>>();

for (Long studentId : studentIdLongs)
{
for (Long standardId : standardIdLongs)
{
.filter("measuredUserId =", studentId)
.filter("standardId =", standardId)
.iterator());
}
}

ArrayList<StandardScoreDAO> ret = new ArrayList<StandardScoreDAO>();

for (Iterator<StandardScoreDAO> i : results)
{
while (i.hasNext())
{
}
}

return ret;
}


As you can see, if there are 100 studentIds and 100 standardIds, this is 10,000 queries. AppEngine will only run 10 in parallel. Aiee! I don't know if it's at all realistic to expect this to finish in 30 seconds (testing soon), but I wonder if anyone sees a much better way to organize this.

With Objectify, you have the option to use the "in" operator in a query. Moreover, it becomes clear from the second block of nested loops that you are only looking for the intersection of the two sets of measuredUserIds and standardIds. So, a single statement should do the trick:

public List<StandardScoreDAO> getStandardScores(
ArrayList<Long> studentIdLongs, ArrayList<Long> standardIdLongs) {
ObjectifyService.register(StandardScoreDAO.class);
Objectify ofy = ObjectifyService.begin();

Iterator<StandardScoreDAO> i = ofy.query(StandardScoreDAO.class)
.filter("measuredUserId in", studentIdLongs)
.filter("standardId in", standardIdLongs)
.iterator();

while (i.hasNext()) {
}

return ret;
}


If you access a list merely by iteration (and not by random access or by index), and do not know its size on creation, LinkedList might give you a performance benefit.

• Are Objectify's "in" operators immune from the 30-sub-query limit? With JDO, for example, I couldn't use studentIdLongs.contains(:measuredUserId) && standardIdLongs.contains(:standardId) because it generates many more than 30 sub-queries. Thanks for the tip on LinkedList - that makes sense! – Riley Apr 13 '11 at 12:55