如何在neo4j .net客户端中使用cypher查询返回两个集合

时间:2013-03-27 12:05:36

标签: neo4jclient

我想在一个查询“tags”和“items”中返回两个集合,其中每个标记可以包含0..many项。看起来如果我使用投影,它会假设一个集合有两列而不是两个集合,这是正确的吗?有没有更好的方法来运行此搜索查询?

我正在"the query response contains columns Tags, Items however ...anonymous type does not contain settable properties to receive this data"

var query =  client
    .Cypher
    .StartWithNodeIndexLookup("tags", "tags_fulltext", keyword)
    .Match("tags<-[:TaggedWith]-items")
    .Return((items, tags) => new 
    {
        Tags = tags.As<Tag>(),
        Items = items.As<Item>()
    });

var results = await query.ResultsAsync;

return new SearchResult
{
    Items = results.Select(x => x.Items).ToList(),
    Tags = results.Select(x => x.Tags).Distinct().ToList()
};

1 个答案:

答案 0 :(得分:3)

选项1

场景:您想要检索与关键字匹配的所有标记,然后为每个标记检索每个项目(以某种方式仍然将它们链接到标记)。

首先,这一行:

.StartWithNodeIndexLookup("tags", "tags_fulltext", keyword)

应该是:

.StartWithNodeIndexLookup("tag", "tags_fulltext", keyword)

也就是说,身份应该是tag而不是tags。这是因为START子句导致一组节点,每个节点都是tag,而不是一组名为tags的节点。语义学,但它会在下一步中使事情变得更简单。

现在我们将其称为tag而不是tags,我们将MATCH子句更新为:

.Match("tag<-[:TaggedWith]-item")

说“对于集合中的每个标签,去找到附在其上的每个项目”。同样,'item'是单数。

现在让我们回复它:

.Return((tag, item) => new 
{
    Tag = tag.As<Tag>(),
    Items = item.CollectAs<Item>()
});

在这里,我们将每个'item'和收集它们放入一组'items'中。我在该代码中对单数与复数的使用是非常具体的。

生成的Cypher表如下所示:

-------------------------
| tag      | items      |
-------------------------
| red      | A, B, C    |
| blue     | B, D       |
| green    | E, F, G    |
-------------------------

最终代码:

var query = client
    .Cypher
    .StartWithNodeIndexLookup("tag", "tags_fulltext", keyword)
    .Match("tag<-[:TaggedWith]-item")
    .Return((tag, item) => new
    {
        Tag = tag.As<Tag>(),
        Items = item.CollectAs<Item>()
    });

但这并不适合你的SearchResult

选项2

场景:您想要检索与关键字匹配的所有标记,然后检索与这些标记中的任何标记匹配的所有项目,但您不必关心将这两个标记链接在一起。< / p>

让我们回到Cypher查询:

START tag=node:tags_fulltext('keyword')
MATCH tag<-[:TaggedWith]-item
RETURN tag, item

那会产生这样的Cypher结果表:

--------------------
| tag      | item  |
--------------------
| red      | A     |
| red      | B     |
| red      | C     |
| blue     | B     |
| blue     | D     |
| green    | E     |
| green    | F     |
| green    | G     |
--------------------

您希望将其中的每一个折叠为一个不相关的标记和项目列表。

我们可以使用collect来执行此操作:

START tag=node:tags_fulltext('keyword')
MATCH tag<-[:TaggedWith]-item
RETURN collect(tag) AS Tags, collect(item) AS Items

-----------------------------------------------------------------------------
| tags                                            | items                   |
-----------------------------------------------------------------------------
| red, red, red, blue, blue, green, green, green  | A, B, C, B, D, E, F, G  |
-----------------------------------------------------------------------------

我们不希望所有这些重复,所以让我们收集不同的:

START tag=node:tags_fulltext('keyword')
MATCH tag<-[:TaggedWith]-item
RETURN collect(distinct tag) AS Tags, collect(distinct item) AS Items

--------------------------------------------
| tags              | items                |
--------------------------------------------
| red, blue, green  | A, B, C, D, E, F, G  |
--------------------------------------------

随着Cypher的工作,将其转换为.NET是一个简单的翻译:

var query = client
    .Cypher
    .StartWithNodeIndexLookup("tag", "tags_fulltext", keyword)
    .Match("tag<-[:TaggedWith]-item")
    .Return((tag, item) => new
    {
        Tags = tag.CollectDistinct<Tag>(),
        Items = item.CollectDistinct<Item>()
    });

摘要

  1. 始终从Cypher开始
  2. 始终从Cypher开始
  3. 当您使用Cypher时,.NET实现应该是一对一的
  4. 的问题?

    我在没有VS支持的文本框中输入了所有这些代码,我还没有测试过任何代码。如果出现问题,请在我们的问题页面上报告完整例外文字和查询。在这里跟踪崩溃很难。在没有完整异常文本,消息,堆栈跟踪等情况下跟踪崩溃只会耗费我的时间,使调试更加困难,并减少我可以花费多少时间来帮助您。