Search code examples
neo4jclient

Returning multiple columns in Neo4jClient Cypher Query


I am using Azure and finding the performance to be slow. In order to reduce the round trip time, I am clubbing the following queries into one query.

var queryItem = _graphClient
            .Cypher
            .Start(new
            {
                n = Node.ByIndexLookup("item_idx", "SKU", sSKU1),
            })
             .Return<Node<Item>>("n");

somewhere else in the code I have following statements

var queryItem = _graphClient
            .Cypher
            .Start(new
            {
                m = Node.ByIndexLookup("item_idx", "SKU", sSKU2),
            })
             .Return<Node<Item>>("m");

I tried to combine above two queries into a single query like this

var queryItem = _graphClient
            .Cypher
            .Start(new
            {
                n = Node.ByIndexLookup("item_idx", "SKU", sSKU1),
                m = Node.ByIndexLookup("item_idx", "SKU", sSKU2),
            })
             .Return<Node<Item>>("n");

I know above is only for single column so I tried using following return statement

.Return((n, m) => new
        {
            N = n.CollectAs<Node<Item>>(),
            M = m.CollectAs<Node<Item>>()
        });

but then I have problems with the following statement

Node<Item> item1 = itemQueryResult.First();

It says Error Cannot implicitly convert type 'AnonymousType#1' to 'Neo4jClient.Node.

Can you please suggest a simple syntax or returning multiple columns and a way to extract the first node? TIA.


Solution

  • I think what you're missing here is that the Return statement returns one object per Cypher row.

    Your query is returning a table like this:

    |-----------------|
    |    n   |   m    |
    |-----------------| 
    |  Node  |  Node  |
    |------------------
    

    That's one table, with one row, with two columns.

    In this statement, you are returning an anonymous type per Cypher row:

    .Return((n, m) => new
    {
        N = n.CollectAs<Node<Item>>(),
        M = m.CollectAs<Node<Item>>()
    });
    

    The return type of that method is IEnumerable<AnonymousType>.

    You're then trying to get the first row (an anonymous type) and implicitly cast that to Node<Item>, which is not valid.

    You should get the row, then get the properties within it.

    Some other things to note:

    • You don't want to use CollectAs in this scenario: that will turn each cell of your table into an array with a single value, which just adds more indirection.
    • .As<Node<T>>() can be written as .Node<T>()

    With that in mind, here's the query you want:

    var result = _graphClient
        .Cypher
        .Start(new
        {
            n = Node.ByIndexLookup("item_idx", "SKU", sSKU1),
            m = Node.ByIndexLookup("item_idx", "SKU", sSKU2),
        })
        .Return((n, m) => new
        {
            N = n.Node<Item>(),
            M = m.Node<Item>()
        })
        .Results
        .Single();
    
    var n = result.N;
    var m = result.M;
    

    Make sense?

    PS: I hope you aren't actually clubbing anything. Baby seals don't like that. You are combining queries.