0

I accidentally created duplicate relationships... now I need to delete them. We got some crazy stuff going on in a cypher answer here how do I delete duplicate relationships between two nodes with cypher?

At first my mind wandered to finding the relationship then checking the count on it. But that's only if I know the two nodes already.

Thoughts?

Update

Maybe I'm missing something, but I don't think this would give me an indication of duplication user.friends.count > 1 as this will count the nodes. I wouldn't know which nodes are counted twice

The only way I can think of getting the other user is to do a second loop. I think this might work if first_rel_to and match_to could be used directly on user without a queryproxy

User.all.each do |user|
  user.friends.each do |friend|
    user.first_rel_to(friend).destroy if (user.match_to(friend).count > 1)   
  end
end

So.. does this have to be done...?

Answer: Yes this has to be done

    User.all.each do |user|
      user.friends.each do |friend|
        user.friends.first_rel_to(friend).destroy if (user.friends.match_to(friend).count > 1)   
      end
    end
Community
  • 1
  • 1
Clam
  • 935
  • 1
  • 12
  • 24
  • Do you want something super efficient or do you want something lazy and easy to run once? – subvertallchris Jan 22 '15 at 04:50
  • my db is fairly small and i was going to just run it in console once. however would be curious in the differences of what u would propose – Clam Jan 22 '15 at 04:58
  • `user.friends.count` returns the count of friends returned by that query, not distinct friends. – subvertallchris Jan 22 '15 at 23:34
  • yeah, but we need to count the relationships between one user and another so i think that 3rd comment in your answer was a typo. i ran the above, in my dev database and i think it works. if you notice anything that i'm missing, you can reply, otherwise i'll make an edit on your answer later and accept – Clam Jan 22 '15 at 23:51

1 Answers1

0

Assuming this is a one-time-only thing, you're using Neo4j.rb 4.1, and you don't have some outrageous number of nodes to examine, here's the easiest way to do it:

User.all.each do |user|
  user.friends.first_rel_to(other_user).destroy if user.friends.match_to(other_user).count > 1
end

Two queries for every user. You'll need to swap out my example for one that returns the count and the first rel for your data but the idea stays the same: use first_rel_to to delete the first relationship between the nodes if match_to that other node tells you that there's more than one rel.

This is also the best use of two of my favorite methods in the gem, first_rel_to and match_to, that I could ever write. This rules. I feel like a proud parent who won't stop bragging about their stupid over-achieving kid.

The downside here is that if you have data stored in that one node, you'll lose it. If you want to be sure you're deleting the right one...

User.all.each do |user|
  if user.friends.match_to(other_user).count > 1
    user.friends.match_to(other_user).each_rel do |rel|
      rel.destroy if rel.this_property.nil?
    end
  end
end

Loop through, if there's more than one rel, loop through the rels, delete the one that you determine is the extraneous relationship.

To avoid this in the future, use the unique: true option on associations or creates_unique_rel in ActiveRel.

Stefan's answer is good if you want something efficient. You'd need to change the START syntax to MATCH.

subvertallchris
  • 5,282
  • 2
  • 25
  • 43
  • good to know my eff up allowed you to showcase this example lol. you said i would lose my node data? do u mean relationship data? possible dumb question: what goes in `other_user` is this automatically known when u do `first_rel_to` on `friends` – Clam Jan 22 '15 at 05:16
  • would i just be putting it on this `has_many :both, :friends, model_class: 'User', rel_class: 'FriendsWith, unique: true'` i have the friends_with declared with activerel, does anything need to be done with that? – Clam Jan 22 '15 at 05:21
  • No, you'd lose the rel data. `other_node` is the other node you have a relationship to. You need to find a way to figure that out; otherwise, just do something like `if user.events.count > 1 then user.friends.each_rel.first.destroy`. – subvertallchris Jan 22 '15 at 14:47
  • i don't think that counts the right thing, see my update in my question and let me know if I'm crazy. – Clam Jan 22 '15 at 20:10
  • I could only find this https://github.com/neo4jrb/neo4j/wiki/Validation-and-Case-Sensitivity-in-Neo4j.rb-3.0 on uniqueness so wasn't 100% sure the right way to implement it with my setup – Clam Jan 23 '15 at 00:12