Wolfgang-Schuetzelhofer / jcypher

Java access to Neo4J graph databases at multiple levels of abstraction
Apache License 2.0
86 stars 15 forks source link

How to return Literal Maps #8

Closed adi closed 8 years ago

adi commented 8 years ago

Hi Wolfgang!

I looked everywhere and I can't find how to obtain the following effect with jcypher:

MATCH (n:Movie) RETURN {name: n.name, extraInfo: n.actorCount, rank:"5/7"}

Can you explain if this is possible and how?

Thank you, Adrian

Wolfgang-Schuetzelhofer commented 8 years ago

Hi Adrian, these kinds of literal maps are currently not supported by JCypher. But here is a code snippet that should achieve the same result:

            JcNode n = new JcNode("n");
    JcString name = new JcString("name");
    JcNumber extraInfo = new JcNumber("extraInfo");
        // if JcString is constructed with a value, the name is ignored
    // and it is taken as a literal
    JcString literal = new JcString(null, "5/7");
    JcString rank = new JcString("rank");
    clauses = new IClause[]{
            MATCH.node(n).label("Movie"),
            RETURN.value(n.property("name")).AS(name),
            RETURN.value(n.property("actorCount")).AS(extraInfo),
            RETURN.value(literal).AS(rank)
    };

    query = new JcQuery();
    query.setClauses(clauses);

    // you can look at the CYPHER query which is generated in the background
    String str = Util.toCypher(query, Format.PRETTY_1);
    System.out.println(str);

    result = dbAccess.execute(query);
            // use a helper method to create the map
            // code of the helper method to be found at the end
    List<Map<JcPrimitive, Object>> maps = resultAsMap(result, name, extraInfo, rank);

    // access values in a map
    Map<JcPrimitive, Object> map = maps.get(0);
    Object v_name = map.get(name);
    Object v_extraInfo = map.get(extraInfo);
    Object v_rank = map.get(rank);

// helper method to create maps private List<Map<JcPrimitive, Object>> resultAsMap(JcQueryResult result, JcPrimitive... key) { List<List<?>> results = new ArrayList<List<?>>(); List<Map<JcPrimitive, Object>> ret = new ArrayList<Map<JcPrimitive,Object>>(); for (JcPrimitive k : key) { List<?> r = result.resultOf(k); results.add(r); for (int i = 0; i < r.size(); i++) { Map<JcPrimitive, Object> map; if (i > ret.size() - 1) { map = new HashMap<JcPrimitive, Object>(); ret.add(map); } else map = ret.get(i); map.put(k, r.get(i)); } } return ret; }

If this functionality really is important to you, I could extend JCypher

I hope that did help, best regards, Wolfgang

Wolfgang-Schuetzelhofer commented 8 years ago

The corrected helper method once again in formatted form:

private List<Map<JcPrimitive, Object>> resultAsMap(JcQueryResult result, JcPrimitive... key) {
    List<List<?>> results = new ArrayList<List<?>>();
    List<Map<JcPrimitive, Object>> ret = new ArrayList<Map<JcPrimitive,Object>>();
    for (JcPrimitive k : key) {
        List<?> r = result.resultOf(k);
        results.add(r);
        for (int i = 0; i < r.size(); i++) {
            Map<JcPrimitive, Object> map;
            if (i > ret.size() - 1) {
                map = new HashMap<JcPrimitive, Object>();
                ret.add(map);
            } else
                map = ret.get(i);
            map.put(k, r.get(i));
        }
    }
    return ret;
}
adi commented 8 years ago

Hi Wolfgang,

Thanks for the explanation. As this was for a project where I needed something working quickly I moved away from JCypher for the moment although I consider it a good project. As such, I don't need the literal map functionality but I think it will be a nice addition in the future.

Thank you again, Adrian