简体   繁体   中英

How to unwind data held in edges with a "common neighbors" style query?

I have a simple model with a single A Document collection

[{ _key: 'doc1', id: 'a/doc1', name: 'Doc 1' }, { _key: 'doc2', id: 'a/doc2', name: 'Doc 2' }]

and a single B Edge collection, joining documents A with an held weight integer on each edge.

[{ _key: 'xxx', id: 'b/xxx', _from: 'a/doc1', _to: 'a/doc2', weight: 256 }]

I'm trying to make a "common neighbors" style query, that takes 2 document as an input, and yields common neighbors of those inputs, along with respective weights (of each side).

For example with doc1 and doc26 input, here is the goal to achieve:

[
  { _key: 'doc6', weightWithDoc1: 43, weightWithDoc26: 57 },
  { _key: 'doc12', weightWithDoc1: 98, weightWithDoc26: 173 },
  { _key: 'doc21', weightWithDoc1: 3, weightWithDoc26: 98 },
]

I successfully started by targeting a single side:

FOR associated, association
  IN 1..1
  ANY ${d1}
  ${EdgeCollection}
  SORT association.weight DESC
  LIMIT 20
  RETURN { _key: associated._key, weight: association.weight }

Then successfully went on with the INTERSECTION logic of the documentation

FOR proj IN INTERSECTION(
  (FOR associated, association
    IN 1..1
    ANY ${d1}
    ${EdgeCollection}
    RETURN { _key: associated._key }),
  (FOR associated, association
    IN 1..1
    ANY ${d2}
    ${EdgeCollection}
    RETURN { _key: associated._key })
)
LIMIT 20
RETURN proj

But I'm now struggling at extracting the weight of each side, as unwinding it on the inner RETURN clauses will make them exclusive on the intersection; thus returning nothing.

Questions:

  1. Is there any way to make some kind of "selective INTERSECTION ", grouping some fields in the process?
  2. Is there an alternative to INTERSECTION to achieve my goal?

Bonus question:

  1. Ideally, after successfully extracting weightWithDoc1 and weightWithDoc26 , I'd like to SORT DESC by weightWithDoc1 + weightWithDoc26

I managed to find an acceptable answer myself

FOR associated IN INTERSECTION(
  (FOR associated
    IN 1..1
    ANY ${doc1}
    ${EdgeCollection}
    RETURN { _key: associated._key }),
  (FOR associated
    IN 1..1
    ANY ${doc2}
    ${EdgeCollection}
    RETURN { _key: associated._key })
)
LET association1 = FIRST(FOR association IN ${EdgeCollection}
  FILTER association._from == CONCAT(${DocCollection.name},'/',MIN([${doc1._key},associated._key])) AND association._to == CONCAT(${DocCollection.name},'/',MAX([${doc1._key},associated._key]))
  RETURN association)
LET association2 = FIRST(FOR association IN ${EdgeCollection}
  FILTER association._from == CONCAT(${DocCollection.name},'/',MIN([${doc2._key},associated._key])) AND association._to == CONCAT(${DocCollection.name},'/',MAX([${doc2._key},associated._key]))
  RETURN association)
SORT (association1.weight+association2.weight) DESC
LIMIT 20
RETURN { _key: associated._key, weight1: association1.weight, weight2: association2.weight }

I believe re-selecting after intersecting is not ideal and not the most performant solution, so I'm leaving it open for now to wait for a better answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM