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

标签 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"}]              │                              │]                             │                              │             │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴─────────────┘

2)所以我不知道该怎么办! 我想要得到created_at youVisited的, visitedYou项目,但我不知道如何在查询期间合并它们,所以我最终弄得一团糟:

  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'),
  };

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

  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) 中执行某些操作,而不是返回两个彼此相关的单独数组,那么这可能会变得容易得多,例如youVisitedyvr ,我只有一个数组,其中的对象包含所有数据 youVisited: [{ user_id, created_at, seen }, ...] 。如何使用 Neo4j 执行此操作?

预计最终result我最终需要的看起来像:

  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,
  };

最佳答案

看起来您已经有了一个有效的解决方案(使用 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

关于javascript - Neo4j - 我有 2 个数据相关的收集。我如何将它们合并在一起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41639613/

相关文章:

javascript - 添加两个相同的事件处理程序是否有默认行为?

neo4j - 从 cypher 中的多个特定路径查询节点

java - 在 neo4j 密码中检索确切的节点 ID

python - 创建索引时死锁

javascript - 如何在Javascript onload事件中实现回调

javascript - 如何检查div前面的滚动位置

neo4j - 如何使用 Cypher/Neo4J 获取所有节点或给定标签的所有属性键?

Neo4j 匹配路径排除具有特定标签的节点

python - py2neo - 由于身份验证失败,客户端未经授权

javascript - 以编程方式更新时不调用 HTML JavaScript onChange 处理程序