Neo4j - 我有2个收集数据相关的地方。我如何将它们合并在一起?

时间:2017-01-13 16:50:19

标签: javascript neo4j cypher

我觉得我在这里做了很多额外的工作,因为有些事我不知道会让事情变得容易多了!

enter image description here

基本上,我正在尝试吸引用户的访问者,以及访问过他们的人。

1)这是我正在使用的当前查询:

MATCH (you:User {user_id: { id }})
WITH you
OPTIONAL MATCH(you)-[yvr:VISIT]->(youVisited:User)
WITH you, collect(youVisited) as youVisited, collect(yvr) as yvr
OPTIONAL MATCH (visitedYou:User)-[vyr:VISIT]->(you)
WITH youVisited, collect(visitedYou) as visitedYou, collect(vyr) as vyr, yvr
RETURN
  youVisited,
  visitedYou,
  yvr,
  vyr,
  length(filter(m in vyr where m.seen = false)) as unseenCount

enter image description here (底部被截断,但youVisitedyvrvisitedYouvyr,右边是unseenCount,但╒══════════════════════════════╤══════════════════════════════╤══════════════════════════════╤══════════════════════════════╤═════════════╕ │"youVisited" │"visitedYou" │"yvr" │"vyr" │"unseenCount"│ ╞══════════════════════════════╪══════════════════════════════╪══════════════════════════════╪══════════════════════════════╪═════════════╡ │[{"user_id":"auth0|58784f52734│[{"user_id":"auth0|5865bfa8087│[{"created_at":1484294208011,"│[{"created_at":1484317325539,"│2 │ │b0307b61ea401"},{"user_id":"au│52725eaaae8f9"},{"user_id":"au│seen":false},{"created_at":148│seen":false},{"created_at":148│ │ │th0|587805cb995ac47e7dbe42ae"}│th0|587805cb995ac47e7dbe42ae"}│4294735987,"seen":false},{"cre│4321428350,"seen":false}] │ │ │,{"user_id":"auth0|5865bfa8087│] │ated_at":1484293423029,"seen":│ │ │ │52725eaaae8f9"},{"user_id":"au│ │false},{"created_at":148429420│ │ │ │th0|58669ac4d4aed25972f7c33e"}│ │1140,"seen":false},{"created_a│ │ │ │,{"user_id":"auth0|586a0337b94│ │t":1484294214268,"seen":false}│ │ │ │a4d77c1f77cb3"}] │ │] │ │ │ └──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴─────────────┘ 就在那里)

created_at

2)所以这就是我不知道该做什么的地方! 我希望得到youVisitedvisitedYou项的 const nodes = { youVisited: row.get('youVisited').map((yv, index) => Object.assign( yv.properties, { created_at: row.get('yvr')[index].properties.created_at }, )), visitedYou: row.get('visitedYou').map((vy, index) => Object.assign( vy.properties, { created_at: row.get('vyr')[index].properties.created_at }, )), unseenCount: row.get('unseenCount'), }; ,但我不知道如何在查询期间合并它们,所以我最终制造这个烂摊子:

  const youVisitedPromises = nodes.youVisited.map(yv => usersIndex.getObject(yv.user_id));
  const visitedYouPromises = nodes.visitedYou.map(vy => usersIndex.getObject(vy.user_id));
  let [youVisited, visitedYou] = await Promise.all([
    youVisitedPromises, visitedYouPromises,
  ].map(Promise.all, Promise));

  youVisited = youVisited.map(yv => Object.assign(
    yv,
    { visited_at: _.get(_.find(nodes.youVisited, { user_id: yv.objectID }), 'created_at') },
  ));
  visitedYou = visitedYou.map(vy => Object.assign(
    vy,
    { visited_at: _.get(_.find(nodes.visitedYou, { user_id: vy.objectID }), 'created_at') },
  ));

  result = {
    youVisited,
    visitedYou,
    unseenCount: nodes.unseenCount,
  };

3)然后我必须获取其他数据并再次找到它...

youVisited

我认为如果我在步骤1)中做了一些事情,这可以变得更容易,而不是返回两个彼此相关的独立数组,例如yvryouVisited: [{ user_id, created_at, seen }, ...],我只有一个包含所有数据result的对象的数组。我如何使用Neo4j?

我最终需要的最终 result = { youVisited: [{ user_id: 'a', nickname: 'foo', visited_at: 12931093 }, ...], visitedYou: [{ user_id: 'b', nickname: 'bar', visited_at: 12931099 }, ...], unseenCount: 1, }; 看起来像是:

  const cypherGetVisitors = `
    MATCH (you:User {user_id: { id }})
    WITH you
    OPTIONAL MATCH(you)-[yvr:VISIT]->(youVisited:User)
    WITH you, collect(youVisited) as youVisited, collect(yvr) as yvr
    OPTIONAL MATCH (visitedYou:User)-[vyr:VISIT]->(you)
    WITH youVisited, collect(visitedYou) as visitedYou, collect(vyr) as vyr, yvr
    RETURN
      youVisited,
      visitedYou,
      yvr,
      vyr,
      length(filter(m in vyr where m.seen = false)) as unseenCount
  `;
  const queryResult = await retry(this.connector._bolt._pool._maxIdle + 1, async () => {
    const session = this.connector.session();
    try {
      const res = await session.run(cypherGetVisitors, { id });
      session.close();
      return res;
    } catch (neo4jError) {
      throw new Error(neo4jError);
    }
  });
  const row = queryResult.records[0];
  const nodes = {
    youVisited: row.get('youVisited').map((yv, index) => Object.assign(
      yv.properties,
      { created_at: row.get('yvr')[index].properties.created_at },
    )),
    visitedYou: row.get('visitedYou').map((vy, index) => Object.assign(
      vy.properties,
      { created_at: row.get('vyr')[index].properties.created_at },
    )),
    unseenCount: row.get('unseenCount'),
  };

  const youVisitedPromises = nodes.youVisited.map(yv => usersIndex.getObject(yv.user_id));
  const visitedYouPromises = nodes.visitedYou.map(vy => usersIndex.getObject(vy.user_id));
  let [youVisited, visitedYou] = await Promise.all([
    youVisitedPromises, visitedYouPromises,
  ].map(Promise.all, Promise));

  youVisited = youVisited.map(yv => Object.assign(
    yv,
    { visited_at: _.get(_.find(nodes.youVisited, { user_id: yv.objectID }), 'created_at') },
  ));
  visitedYou = visitedYou.map(vy => Object.assign(
    vy,
    { visited_at: _.get(_.find(nodes.visitedYou, { user_id: vy.objectID }), 'created_at') },
  ));

  result = {
    youVisited,
    visitedYou,
    unseenCount: nodes.unseenCount,
  };

如果还有其他任何可以提供帮助的完整代码:

{{1}}

2 个答案:

答案 0 :(得分:1)

看起来您已经有了一个正常工作的解决方案(使用COLLECT()以及您想要的值的新地图。)

如果您确实需要所有值+更多,您可以使用3.1 map projection功能,这样可以更轻松地包含节点的部分或全部属性以及您希望存在的其他属性返回的结构。

使用您的查询片段的示例:

OPTIONAL MATCH(you)-[yvr:VISIT]->(youVisited:User)
WITH you, collect(youVisited {.*, created_at: yvr.created_at}) as youVisted

在这种情况下,。*表示包含节点的所有属性(youVisited),但如果您只需要某些属性,则只能包含相关的键,并且键/值对将包含在返回的映射中。因此,如果您只需要user_id和created_at,那么这将起作用:

OPTIONAL MATCH(you)-[yvr:VISIT]->(youVisited:User)
WITH you, collect(youVisited {.user_id, created_at: yvr.created_at}) as youVisted

答案 1 :(得分:0)

所以我发现我可以在收集过程中构建一个对象。这有什么问题,或者更好的方法吗?

MATCH (you:User {user_id: { id }})
WITH you
OPTIONAL MATCH(you)-[yvr:VISIT]->(youVisited:User)
WITH you, collect({user_id: youVisited.user_id, created_at: yvr.created_at}) as youVisited
OPTIONAL MATCH (visitedYou:User)-[vyr:VISIT]->(you)
WITH youVisited, collect({user_id: visitedYou.user_id, created_at: vyr.created_at}) as visitedYou, collect(vyr) as vyr
RETURN
  youVisited,
  visitedYou,
  length(filter(m in vyr where m.seen = false)) as unseenCount

enter image description here

在我从其他来源获取其余数据后,我仍然需要完成所有其他地图工作,但这与Neo4j无关。