在 Neo4j.rb 中设置 "friends"(双向关系)的正确方法
Proper way to set up "friends" (bidirectional relationship) in Neo4j.rb
在具有双向关系的 User
之间创建关系的正确方法是什么?
假设我有:
class User
include Neo4j::ActiveNode
property :name, type: String
property :created_at, type: DateTime
property :updated_at, type: DateTime
has_many :both, :friends, model_class: 'User', type: 'connection' unique: true
has_many :in, :followers, model_class: 'User', type: 'connection', unique: true
has_many :out, :following, model_class: 'User', type: 'connection', unique: true
end
然后,
users = [
User.create(name: 'Foo'),
User.create(name: 'Bar'),
User.create(name: 'Baz'),
]
这样做合适吗?这似乎非常低效:
users.each do |user|
user.friends << users.reject { |u| u == user }
end
如果你想确保 user.friends
returns 其他两个用户,我实际上会这样做:
users.each do |user|
other_users = users.reject { |u| u == user || user.friends.include?(u) }
user.friends << other_users
end
现在 效率极低!它创建一个新数组并针对每个用户对数据库执行额外的查找。 (FWIW,include?
查找非常快。您也可以删除 reject
并再次遍历 users
以加快速度。)仍然有必要完成此操作,否则,您将创建重复的关系。
在你的协会中设置unique: true
只会在一个方向上拯救你。针对 has_many :both
关联的查询使用方向不可知的 Cypher MATCH
但 CREATE
操作始终需要方向,因此它们从左侧的节点到右侧的节点。 user1.friends << user2
和 user2.friends << user1
将在两个节点之间创建两个关系,每个方向一个。
编辑
正如您在 your own comment 中针对 Neo4j.rb 上的问题指出的那样,使用 user.friends = [other_friends]
将始终清除所有现有关系并防止重复。这是解决问题的一种非常酷的方法。
在具有双向关系的 User
之间创建关系的正确方法是什么?
假设我有:
class User
include Neo4j::ActiveNode
property :name, type: String
property :created_at, type: DateTime
property :updated_at, type: DateTime
has_many :both, :friends, model_class: 'User', type: 'connection' unique: true
has_many :in, :followers, model_class: 'User', type: 'connection', unique: true
has_many :out, :following, model_class: 'User', type: 'connection', unique: true
end
然后,
users = [
User.create(name: 'Foo'),
User.create(name: 'Bar'),
User.create(name: 'Baz'),
]
这样做合适吗?这似乎非常低效:
users.each do |user|
user.friends << users.reject { |u| u == user }
end
如果你想确保 user.friends
returns 其他两个用户,我实际上会这样做:
users.each do |user|
other_users = users.reject { |u| u == user || user.friends.include?(u) }
user.friends << other_users
end
现在 效率极低!它创建一个新数组并针对每个用户对数据库执行额外的查找。 (FWIW,include?
查找非常快。您也可以删除 reject
并再次遍历 users
以加快速度。)仍然有必要完成此操作,否则,您将创建重复的关系。
在你的协会中设置unique: true
只会在一个方向上拯救你。针对 has_many :both
关联的查询使用方向不可知的 Cypher MATCH
但 CREATE
操作始终需要方向,因此它们从左侧的节点到右侧的节点。 user1.friends << user2
和 user2.friends << user1
将在两个节点之间创建两个关系,每个方向一个。
编辑
正如您在 your own comment 中针对 Neo4j.rb 上的问题指出的那样,使用 user.friends = [other_friends]
将始终清除所有现有关系并防止重复。这是解决问题的一种非常酷的方法。