利用Neo4jClient的OrderBy问题

时间:2014-12-01 20:59:50

标签: cypher neo4jclient

我按照传出关系的数量对大型数据库进行排序。我有一个有效的Cypher查询如下:

optional match (n)-[r]->(m)
return n, Count(r) as c
order by c DESC limit 1;

Cypher查询正如预期的那样工作。但是,当我正在调试并逐步完成Cypher时 - > Neo4jClient转换,我似乎无法找到问题的根源。

public ReturnPayload[] getByConnections()
    {
        var query = client.Cypher
            .OptionalMatch("(p)-[r]->(m)")
            .Return((p, r, m, c) => new
            {
                p = p.As<Person>(),
                pid = (int)p.Id(),
                e = r.As<RelationshipInstance<Object>>(),
                m = m.As<Metadata>(),
                c = r.Count()
            }).OrderByDescending("c").Limit(1);

        var res = query.Results;
        var payload = new List<ReturnPayload>();
        foreach (var el in res)
        {
            var t = new ReturnPayload();
            t.e = el.e;
            t.m = el.m;
            t.pid = el.pid;
            t.p = el.p;
            payload.Add(t);
        }

        return payload.ToArray<ReturnPayload>();
    }

我怀疑问题的一部分可能是我没有使用CollectAs<T>()因此它指的是每个人的'1'计数。不幸的是,我尝试使用CollectAs<T>()CollectAsDisctinct<T>(),我的结果JSON架构只是将每个单独的元素包装在一个数组中,而不是将相同的元素聚合到一个正确的数组中。

FOREACH循环用于帮助从匿名类型转换为我的相对标准<ReturnPayload>,它在其参数中不使用c对象。

感谢您的时间,谢谢。

调试查询测试:

OPTIONAL MATCH (p)-[r]->(m)
RETURN p AS p, id(p) AS pid, r AS e, m AS m, count(r) AS c
ORDER BY c DESC
LIMIT {p0}

我的'功能'Cypher查询:

optional match (n)-[r]->(m)
return n, Count(r) as c
order by c DESC limit 1;

1 个答案:

答案 0 :(得分:1)

所以,你已经确定自己正在运行两个不同的查询。这就是问题:您的C#与您期望的Cypher不匹配。

要使C#与正在工作的Cypher匹配,请将其更改为:

    var query = client.Cypher
        .OptionalMatch("(n)-[r]->(m)")
        .Return((n, r) => new
        {
            n = n.As<Person>(),
            c = r.Count()
        })
        .OrderByDescending("c")
        .Limit(1);

现在应该生成相同的查询,因此产生的效果与您在Cypher工作中所期望的相同。

在纯粹的风格说明中,您还可以将foreach查询简化为更具功能性的等价物:

var payload = query
    .Results
    .Select(r => new ReturnPayload {
        n = r.n,
        c = r.c
    })
    .ToArray();
return payload;

然而,当我仔细查看你的查询时,看起来你只是为了获得前1而想要计数,然后你就把它扔掉了。

考虑使用WITH子句:

optional match (n)-[r]->(m)
with n as n, count(r) as c
order by c desc
limit 1
return n

您可以使用类似的语法将其映射回C#:

var query = client.Cypher
    .OptionalMatch("(n)-[r]->(m)")
    .With((n, r) => new
    {
        n = n.As<Person>(),
        c = r.Count()
    })
    .OrderByDescending("c")
    .Limit(1)
    .Return(n => new ReturnPayload      // <-- Introduce the type here too
    {
        n = n.As<Person>()
    });

然后,您不需要查询数据,只需将其与另一个foreach循环一起丢弃即可。 (您会注意到我在Return调用中也引入了DTO类型,因此您也不必将其从匿名类型中转换出来。)

(免责声明:我只是直接在答案中输入所有这些C#;我没有仔细检查过编辑,所以我的签名可能会稍微关闭。)

希望有所帮助!