BaseDocuments in v4 Java Driver

216 views
Skip to first unread message

Rob Keevil

unread,
Oct 27, 2016, 3:42:52 AM10/27/16
to ArangoDB
Hi,

I'm testing the new java driver, which gives a nice speed up over the v3 driver.  I have two questions however that I can't figure out from the docs.

Firstly, what object type do I use if the return from arangoDB isn't a document?  One query I'm using returns pairs of documents, so therefore doesn't have _key, id etc at the root.  This causes a VPackParserException.  Previously I returned this as a raw Json result, but that doesn't seem to be available anymore.

Secondly, how do I access nested objects in a BaseDocument?  I can see that in the VPackSlice format I can just do doc.get("document1").get("_key").getAsString, but I can't find an equivalent for BaseDocuments.  Annoyingly if I use VPackSlice instead it seems to send Apache Flink's memory manager crazy.

Thanks,
Rob

mpv1989

unread,
Oct 27, 2016, 4:56:26 AM10/27/16
to ArangoDB
Hi Rob,

If your return type is not a document you have 4 options:

1. use String as return type, which give you a raw json
ArangoCursor<String> cursor = arangoDB.db().query("your query", null, null, String.class);

2. use VPackSlice as return type, get the documents from it and deserialize them with the class VPack to BaseDocument
VPack deserialiser = new VPack.Builder().build();
ArangoCursor<VPackSlice> cursor = arangoDB.db().query("your query", null, null, VPackSlice.class);

for (; cursor.hasNext();) {
 
VPackSlice vpack = cursor.next();
 
BaseDocument doc1 = deserialiser.deserialize(vpack.get("document1"), BaseDocument.class);
  BaseDocument doc2 = deserialiser.deserialize(vpack.get("document2"), BaseDocument.class);
}

3. use Map as return type
ArangoCursor<Map> cursor = arangoDB.db().query("your query", null, null, Map.class);
for (; cursor.hasNext();) {
 
Map<String, Object> result = cursor.next();
 
Map<String, Object> document1 = (Map<String, Object>) result.get("document1");
  Map<String, Object> document2 = (Map<String, Object>) result.get("document2");
}


4. make your own POJO which reflect your qery result and use it as return type
public class MyResult {
  private BaseDocument document1;
  private BaseDocument document2;

  public MyResult() {
    super();
  }

  // setter + getter
}

ArangoCursor<MyResult> cursor = arangoDB.db().query("your query", null, null, MyResult.class);
for (; cursor.hasNext();) {
  MyResult result = cursor.next();
  BaseDocument document1 = result.getDocument1();
  BaseDocument document2 = result.getDocument2();
}


If you have nested objects and want to use BaseDocument, you can access them with getAttribute(key) and cast the Object result to Map<String, Object> like in option 3.
BaseDocument baseDocument = ...
Map<String, Object> nestedObj = (Map<String, Object>) baseDocument.getAttribute("nestedObjKey");

Generally you do not have to use BaseDocument. It is just a little helper for small things, where you do not have a POJO for. The driver automatically de-/serialize your POJOs when insert/get/update/replace or query.
The de-/serialization is highly configurable. see documentation: https://github.com/arangodb/arangodb-java-driver/blob/master/docs/serialization.md

For additional examples of working with the different types for documents, take a look here: https://github.com/arangodb/arangodb-java-driver/tree/master/src/test/java/com/arangodb/example/document


Mark

Rob Keevil

unread,
Oct 27, 2016, 5:17:35 AM10/27/16
to ArangoDB
Thanks very much for the thorough answer!  As the return object may have different fields per document (making POJOs difficult), I went for option 3, the Map.

Rob Keevil

unread,
Oct 28, 2016, 11:40:59 AM10/28/16
to ArangoDB
One follow up question: I'm finding that with the Map option I also get a exception if the query has more than one document returned, e.g.:
FOR v, e IN 1..3 OUTBOUND 'persons/eve' GRAPH 'knows_graph' RETURN {v: v, e: e}
Trying to load the result of this query as a Map causes the following exception:
Caused by: com.arangodb.ArangoDBException: com.arangodb.velocypack.exception.VPackParserException: java.lang.NullPointerException
	at com.arangodb.internal.ArangoExecutor.deserialize(ArangoExecutor.java:139)
	at com.arangodb.internal.ArangoCursorIterator.next(ArangoCursorIterator.java:67)
Is this expected behaviour, do maps onlly work for single documents?

Rob Keevil

unread,
Oct 31, 2016, 6:12:19 AM10/31/16
to ArangoDB
On further inspection I suspect this is a bug.  The query:
FOR v, e IN 1..3 OUTBOUND 'persons/eve' GRAPH 'knows_graph' RETURN {v:v, e: e}
errors the java driver with a null pointer, whether I use a Map or BaseDocument

The equivalent query:
FOR v, e IN 1..3 OUTBOUND 'persons/eve' GRAPH 'knows_graph' RETURN {v: {"_key": v._key, "_id": v._id, "_rev": v._rev, "name": v.name}, e: {"_key": e._key, "_id": e._id, "_rev": e._rev, "_from":e._from, "_to":e. _to}}
works for both types.

mpv1989

unread,
Nov 2, 2016, 8:19:43 AM11/2/16
to ArangoDB
This is a bug in the DB in version 3.1.RC2 and 3.1.RC3. It is fixed in final version 3.1, which we release at the moment. It should be available in the next 1-2 days.
With that version you need the java driver in version 4.1.0, because we changed the velocystream protocol in the DB version 3.1, to remove the need of an extra velocystream endpoint. Driver version 4.1.0 only works with the final release and not with the RCs.

You can use Map for every result, not only for sinlge documents. Your approach, to use Map for these queries, is correct and will work when ArangoDB 3.1 is released.
Reply all
Reply to author
Forward
0 new messages