1

Suppose we have

  • Node: User
    • name : String
  • Rel: Transaction
    • amount : Float

representing a simplized Bitcoin-like transaction, where a User sends coins to other Users. A Transaction has a property amount which shows how much coin you're sending to the to_node from from_node.

Then now I want to get all the transactions (either uni- or bi- directionally) between Alice and Bob. How can I do this?

# user.rb
has_many :out, :receivers, rel_class: :Transaction
has_many :in, :senders, rel_class: :Transaction


# Console
alice = User.find_by(name: "Alice")
bob = User.find_by(name: "Bob")

# I want to do something like this:
Transaction.between(from: alice, to: bob)

# or this:
alice.receivers.rel_where(to_node: bob)

I was surprised that the latter isn't acceptable. It includes bob directly into CYPHER.

Using Neo4jrb v8.0.0

Todoroki
  • 515
  • 4
  • 12

1 Answers1

0

I struggled and came to know I can do something like this:

alice.receivers.match_to(bob).pluck(:rel1)

With this we can get all the transactions sent from alice to bob, but I think it's not a good idea using the magical :rel1 here (which is available because it is automatically written in the CYPHER, and match_to returns a QueryProxy object: match_to)

But it is always not much encouraged to get just the Rels.
Relatively, we could

alice.receivers.match_to(bob).rel_where(amount: 1.0)   # Txs which amount are 1.0btc

and

alice.receivers.match_to(bob).each_rel.sum {|rel| rel.amount }   # All the sent money!

 
Note that you can't do this (somehow):

alice.receivers.match_to(bob).rel_where("rel1.amount < 10.0")

but can go-around with this:

query = alice.receivers.match_to(bob)          # create just the query
query.where("#{query.rel_var}.amount < 10.0")  # you can get `:rel1` by `rel_var`
Todoroki
  • 515
  • 4
  • 12
  • And now I noticed another: you can get all Rels by `rels` and only the first one by `rel`, like `alice.receivers.match_to(bob).rels`. But this can be deprecated (especially `rel`, see [this](https://github.com/neo4jrb/neo4j/issues/697)) so it's not encouraged to do this – Todoroki Feb 13 '17 at 15:07
  • FYI you can pass arguments to an association to define the node / rel variables like: `alice.receivers(:node_var, :rel_var)` – Brian Underwood Feb 13 '17 at 20:01
  • @BrianUnderwood : Oh thank you, so that is the way to do it... I've looked at [the issue to add Rel querying](https://github.com/neo4jrb/neo4j/issues/697), but it seemed not developed yet (and it said it would be `.where(node_var: , rel_var: )` or `where(node_var).rel(rel_var)`). Also, it returns nothing [when you go searching in the document](http://neo4jrb.readthedocs.io/en/8.0.x/search.html?q=node_var&check_keywords=yes&area=default#). – Todoroki Feb 16 '17 at 11:40
  • wait, `alice.receivers(node_var: {uuid: bob.uuid}, rel_node: {amount: 1.0})` seems not to work for me. Am I missing something? Also, you cannot string query in this way..? (like `.query_as(:rel).where("rel.amount < 100")` ) – Todoroki Feb 16 '17 at 11:43
  • `node_var` is not something that we implemented (and we probably won't). You could either do `alice.receivers(:node_var, :rel_var).where("node_var.uuid = ? AND rel_var.amount = 1.0", bob.uuid)` or probably better `alice.receivers.where(uuid: bob.uuid).rel_where(amount: 1.0)` – Brian Underwood Feb 17 '17 at 18:20
  • For the second one you might do `alice.receivers(nil, :rel).where("rel.amount < 100")` – Brian Underwood Feb 17 '17 at 18:20