App Engine Java: syntax for setting query limit and start offset. - java

I have a list of games in GAE datastore and I want to query fixed number of them, starting from a certain offset, i.e. get next 25 games starting form entry with id "75".
PersistenceManager pm = PMF.get().getPersistenceManager(); // from Google examples
Query query = pm.newQuery(Game.class); // objects of class Game are stored in datastore
query.setOrdering("creationDate asc");
/* querying for open games, not created by this player */
query.setFilter("state == Game.STATE_OPEN && serverPlayer.id != :playerId");
String playerId = "my-player-id";
List<Game> games = query.execute(playerId); // if there's lots of games, returned list has more entries, than user needs to see at a time
//...
Now I need to extend that query to fetch only 25 games and only games following entry with id "75". So the user can browse for open games, fetching only 25 of them at a time.
I know there's lots of examples for GAE datastore, but those all are mostly in Python, including sample code for setting limit on the query.
I am looking for a working Java code sample and couldn't find one so far.

It sounds like you want to facilitate paging via Query Cursors. See: http://code.google.com/appengine/docs/java/datastore/queries.html#Query_Cursors
From the Google doc:
public class ListPeopleServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Query q = new Query("Person");
PreparedQuery pq = datastore.prepare(q);
int pageSize = 15;
resp.setContentType("text/html");
resp.getWriter().println("<ul>");
FetchOptions fetchOptions = FetchOptions.Builder.withLimit(pageSize);
String startCursor = req.getParameter("cursor");
// If this servlet is passed a cursor parameter, let's use it
if (startCursor != null) {
fetchOptions.startCursor(Cursor.fromWebSafeString(startCursor));
}
QueryResultList<Entity> results = pq.asQueryResultList(fetchOptions);
for (Entity entity : results) {
resp.getWriter().println("<li>" + entity.getProperty("name") + "</li>");
}
resp.getWriter().println("</ul>");
String cursor = results.getCursor().toWebSafeString();
// Assuming this servlet lives at '/people'
resp.getWriter().println(
"<a href='/people?cursor=" + cursor + "'>Next page</a>");
}
}

Thanks everyone for help. The cursors was the right answer.
The thing is that I am pretty much stuck with JDO and can't use DatastoreService, so I finally found this link:
http://code.google.com/appengine/docs/java/datastore/jdo/queries.html#Query_Cursors

Related

Using dynamic query for spring mvc pagination

I am trying to implement pagination in spring mvc.
In my case, I have a Review entity which consists of reviewStatus and the date it was submitted on.
I am trying to use JpaRepository, but I am not sure how to support the following search query using it.
SELECT * from review WHERE review.reviewStatus = 2 AND
( review.submittedOn BETWEEN '2015-09-08' AND '2015-09-09' )
I can see(refer http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/jpa.repositories.html) that we can define methods for particular queries like findbyname.
However, in my case, if the user doesn't provide status then the above query simply becomes:
SELECT * from review WHERE ( review.submittedOn BETWEEN
'2015-09-08' AND '2015-09-09' )
and if there is no submitted date provided, it becomes
SELECT * from review WHERE review.reviewStatus = 2
In short, the query depends upon the values entered by the end-user and I wish to use the same parameters to implement pagination.
Please guide and/or share links to implement same.
Thanks in advance.
Have a look at http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/PagingAndSortingRepository.html
You can pass a Pageable object into the findAll method
http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Pageable.html
As per http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-seven-pagination/
public List<Person> search(String searchTerm, int pageIndex) {
LOGGER.debug("Searching persons with search term: " + searchTerm);
//Passes the specification created by PersonSpecifications class and the page specification to the repository.
Page requestedPage = personRepository.findAll(lastNameIsLike(searchTerm), constructPageSpecification(pageIndex));
return requestedPage.getContent();
}
/**
* Returns a new object which specifies the the wanted result page.
* #param pageIndex The index of the wanted result page
* #return
*/
private Pageable constructPageSpecification(int pageIndex) {
Pageable pageSpecification = new PageRequest(pageIndex, NUMBER_OF_PERSONS_PER_PAGE, sortByLastNameAsc());
return pageSpecification;
}
have a look this for spring mvc paging: How to implement pagination in Spring MVC 3
As for you dynamic query, you may use a Stringbuilder to build your query based on user input. Somewhere along the lines of:
pulic YourDomainObject searchDynamically(String reviewStatus, String date){
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM review WHERE ");
if(null != reviewStatus && null != date){
sql.append(" reviewStatus = ? and date = ? ");
}elseif(null != reviewStatus){
sql.append(" reviewStatus = ? ");
}elseif(null != date){
sql.append(" date = ? ");
}
}

NullpointerException while querying for the Datastore statistics in App Engine Java Servlet

Within my app's Servlet, I want to control wether its Datastore is empty or not (the first time I run the servlet it will be empty, but that's not the case right now as I already have populated it and made it persistent) before continuing with the rest of the code. In this Datastore Docs I discovered a way of querying the datastore and fetch different kind of statistics.
But while executing:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity globalStat = datastore.prepare(new Query("__Stat_Total__")).asSingleEntity();
Long totalBytes = (Long) globalStat.getProperty("bytes");
Long totalEntities = (Long) globalStat.getProperty("count");
I get a NullPointerException when I try to store the two Long variables.
Why is the Entity globalStat object null after the query?
EDIT 1: Additional information
I'm trying to get the Datastore statistics just after populating it with a List<Entity> of Entities:
public class MyServlet extends HttpServlet {
ArrayList<Tour> m_tours = new ArrayList<Tour>();
Key tourKey;
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
//.... some code
private DatastoreService populateDatastore(){
//... some other code ...
List<Entity> List = Arrays.asList(tour,tour1,tour2,tour3,
tour4,tour5,tour6,tour7,tour8);
datastore.put(List);
Entity globalStat = datastore.prepare(
new Query("__Stat_Total__")).asSingleEntity();
try{
Long totalEntities = (Long) globalStat.getProperty("count");
Long totalBytes = (Long) globalStat.getProperty("bytes");
}catch (NullPointerException e){
e.printStackTrace();
}`
}
}
and just this instructions the Entity globalstat object still shows to be null in the debugging tool:
how come that the new Query("__Stat_Total__")).asSingleEntity(); doesn't produce any result when I just filled the datastore with several entities?
ANSWER:
as reported here: Using App Engine Datastore Low Level API with Java,
"Stat_Total" and "Stat_Kind" don't work in a local development server. They only work when deployed in App Engine Server.

Neo4j ExecutionEngine does not return valid results

Trying to use a similar example from the sample code found here
My sample function is:
void query()
{
String nodeResult = "";
String rows = "";
String resultString;
String columnsString;
System.out.println("In query");
// START SNIPPET: execute
ExecutionEngine engine = new ExecutionEngine( graphDb );
ExecutionResult result;
try ( Transaction ignored = graphDb.beginTx() )
{
result = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n, n.Name" );
// END SNIPPET: execute
// START SNIPPET: items
Iterator<Node> n_column = result.columnAs( "n" );
for ( Node node : IteratorUtil.asIterable( n_column ) )
{
// note: we're grabbing the name property from the node,
// not from the n.name in this case.
nodeResult = node + ": " + node.getProperty( "Name" );
System.out.println("In for loop");
System.out.println(nodeResult);
}
// END SNIPPET: items
// START SNIPPET: columns
List<String> columns = result.columns();
// END SNIPPET: columns
// the result is now empty, get a new one
result = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n, n.Name" );
// START SNIPPET: rows
for ( Map<String, Object> row : result )
{
for ( Entry<String, Object> column : row.entrySet() )
{
rows += column.getKey() + ": " + column.getValue() + "; ";
System.out.println("nested");
}
rows += "\n";
}
// END SNIPPET: rows
resultString = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n.Name" ).dumpToString();
columnsString = columns.toString();
System.out.println(rows);
System.out.println(resultString);
System.out.println(columnsString);
System.out.println("leaving");
}
}
When I run this in the web console I get many results (as there are multiple nodes that have an attribute of Name that contains the pattern 79. Yet running this code returns no results. The debug print statements 'in loop' and 'nested' never print either. Thus this must mean there are not results found in the Iterator, yet that doesn't make sense.
And yes, I already checked and made sure that the graphDb variable is the same as the path for the web console. I have other code earlier that uses the same variable to write to the database.
EDIT - More info
If I place the contents of query in the same function that creates my data, I get the correct results. If I run the query by itself it returns nothing. It's almost as the query works only in the instance where I add the data and not if I come back to the database cold in a separate instance.
EDIT2 -
Here is a snippet of code that shows the bigger context of how it is being called and sharing the same DBHandle
package ContextEngine;
import ContextEngine.NeoHandle;
import java.util.LinkedList;
/*
* Class to handle streaming data from any coded source
*/
public class Streamer {
private NeoHandle myHandle;
private String contextType;
Streamer()
{
}
public void openStream(String contextType)
{
myHandle = new NeoHandle();
myHandle.createDb();
}
public void streamInput(String dataLine)
{
Context context = new Context();
/*
* get database instance
* write to database
* check for errors
* report errors & success
*/
System.out.println(dataLine);
//apply rules to data (make ContextRules do this, send type and string of data)
ContextRules contextRules = new ContextRules();
context = contextRules.processContextRules("Calls", dataLine);
//write data (using linked list from contextRules)
NeoProcessor processor = new NeoProcessor(myHandle);
processor.processContextData(context);
}
public void runQuery()
{
NeoProcessor processor = new NeoProcessor(myHandle);
processor.query();
}
public void closeStream()
{
/*
* close database instance
*/
myHandle.shutDown();
}
}
Now, if I call streamInput AND query in in the same instance (parent calls) the query returns results. If I only call query and do not enter ANY data in that instance (yet web console shows data for same query) I get nothing. Why would I have to create the Nodes and enter them into the database at runtime just to return a valid query. Shouldn't I ALWAYS get the same results with such a query?
You mention that you are using the Neo4j Browser, which comes with Neo4j. However, the example you posted is for Neo4j Embedded, which is the in-process version of Neo4j. Are you sure you are talking to the same database when you try your query in the Browser?
In order to talk to Neo4j Server from Java, I'd recommend looking at the Neo4j JDBC driver, which has good support for connecting to the Neo4j server from Java.
http://www.neo4j.org/develop/tools/jdbc
You can set up a simple connection by adding the Neo4j JDBC jar to your classpath, available here: https://github.com/neo4j-contrib/neo4j-jdbc/releases Then just use Neo4j as any JDBC driver:
Connection conn = DriverManager.getConnection("jdbc:neo4j://localhost:7474/");
ResultSet rs = conn.executeQuery("start n=node({id}) return id(n) as id", map("id", id));
while(rs.next()) {
System.out.println(rs.getLong("id"));
}
Refer to the JDBC documentation for more advanced usage.
To answer your question on why the data is not durably stored, it may be one of many reasons. I would attempt to incrementally scale back the complexity of the code to try and locate the culprit. For instance, until you've found your problem, do these one at a time:
Instead of looping through the result, print it using System.out.println(result.dumpToString());
Instead of the regex query, try just MATCH (n) RETURN n, to return all data in the database
Make sure the data you are seeing in the browser is not "old" data inserted earlier on, but really is an insert from your latest run of the Java program. You can verify this by deleting the data via the browser before running the Java program using MATCH (n) OPTIONAL MATCH (n)-[r]->() DELETE n,r;
Make sure you are actually working against the same database directories. You can verify this by leaving the server running. If you can still start your java program, unless your Java program is using the Neo4j REST Bindings, you are not using the same directory. Two Neo4j databases cannot run against the same database directory simultaneously.

How can I send from the server-side (Google App Engine, Cloud Endpoints) the information to my client?

I have an Android Application that is stored in the Cloud, with Google App Engine. I use Cloud Endpoints. My problem is that I cannot send the data from the server to my client(Android Device), or better said, so far, I have no idea how to do that.
So far, I have managed to insert data in the datastore, by creating an endpoint and calling the method that is in charge with adding a record in the database(that's located on the server side, in myProject - AppEngine) , using the following code (on the client):\
Noteendpoint.Builder endpointBuilder = new Noteendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) { }
});
Noteendpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
// Construct the note.
Note note = new Note().setDescription("Note DescriptionRoxana");
String noteID = new Date().toString();
note.setId(noteID);
note.setEmailAddress("E-Mail AddressRoxana");
// Insert the Note, by calling a method that's on the server side - insertNote();
Note result = endpoint.insertNote(note).execute();
} catch (IOException e) {
e.printStackTrace();
}
But I cannot see a way of retrieving data from the datastore and to display it on the server side. I tried to do the same, create an endpoint, that will call the method that retrieves all the records in the database (method that is located on the server), but my application crashes.
The code for the method that retrieves data from the datastore is the following:
public CollectionResponse<Note> listNote(
#Nullable #Named("cursor") String cursorString,
#Nullable #Named("limit") Integer limit) {
EntityManager mgr = null;
Cursor cursor = null;
List<Note> execute = null;
try {
mgr = getEntityManager();
Query query = mgr.createQuery("select from Note as Note");
if (cursorString != null && cursorString != "") {
cursor = Cursor.fromWebSafeString(cursorString);
query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
}
if (limit != null) {
query.setFirstResult(0);
query.setMaxResults(limit);
}
execute = (List<Note>) query.getResultList();
cursor = JPACursorHelper.getCursor(execute);
if (cursor != null)
cursorString = cursor.toWebSafeString();
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (Note obj : execute)
;
} finally {
mgr.close();
}
return CollectionResponse.<Note> builder().setItems(execute)
.setNextPageToken(cursorString).build();
}
You see, the returned type is collection response. You have access to this type of data, after performing the following import:
import com.google.api.server.spi.response.CollectionResponse;
I inferred that this is a data type characteristic to the server side, thus, I have no idea how I can cast it into a List, ArrayList, or any other type of collection, that can be used on the client side.
How should I do it then? Since adding data was so easy and so straight forward, I have assumed that retrieving data would be performed in the same manner, but apparently I am missing something essential for this matter.
Thank you in advance!
The classes you use in the backend are not the same as the classes you'll use in the client. Endpoints will generate a set of libraries for you, either on the command line or with tooling like Google Plugin for Eclipse. See Using Endpoints in an Android Client.
The generated class representing the collection of Notes in your example will be named something like NotesCollection. This object will have a method getItems, which provides you a List<Note> you can iterate on in your Android application.
Similar to having an endpoint for inserting data into a datastore model(methods of type POST), you need to have an endpoint for querying the data from the datastore model (methods of type GET). After you define both these methods, you need generate your discovery document and client library so that clients know about both these methods and can call them. If your speaking about displaying the data in the web itself then you can build a Javascript client by using the required client library.

Google Appengine - Object with id "com.google.appengine.api.datastore.Key:Product("Potatoe")" is managed by a different Object Manager

Hi i am hitting the common error "managed by a different object manager"
I have looked around online and not found a solution that fits my problem. I am calling the following code from a JSP page
PersistenceManager pm = PMF.get().getPersistenceManager();
String query = "SELECT FROM " +Location.class.getName();
List<Location> locTs = (List<Location>) pm.newQuery(query).execute();
for (Location location : locTs) {
location.genRes(pm);
}
pm.close();
return "done";
location.genRes
public void genRes(PersistenceManager pm) {
Key product = this.getLtype(pm).getProductKey();
String query = "SELECT FROM " + LocationInventry.class.getName() + " WHERE location == '"+key.getId()+"' && product == '"+product.getId()+"'";
List<LocationInventry> lvd = (List<LocationInventry>) pm.newQuery(query).execute();
if (lvd.size() == 0 ) {
LocationInventry locationInventry = new LocationInventry(product, this);
pm.makePersistent(locationInventry);
}
else {
lvd.get(0).gen();
}
}
The error is being thrown on pm.makePersistent(locationInventry);
As far as I can tell I am using only one persistent management and I am closing it after use. Thanks for any help.
Object with id "com.google.appengine.api.datastore.Key:Product("Potatoe")" is managed by a different Object Manager
org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:375)
org.datanucleus.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:674)
org.datanucleus.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:694)
net.sparktank.quilage.datastore.Location.genRes(Location.java:220)
net.sparktank.quilage.server.MainRunner.genResources(MainRunner.java:239)
org.apache.jsp.server.generateResources_jsp._jspService(generateResources_jsp.java:45)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
I had this same problem some time ago and I have a vague memory that my jdoconfig.xml file was missing or not configured correctly.
Check out http://code.google.com/appengine/docs/java/datastore/usingjdo.html for more details.

Categories

Resources