【问题标题】:Neo4j gem - Preferred method to deal with admin relationshipNeo4j gem - 处理管理员关系的首选方法
【发布时间】:2015-01-24 01:27:18
【问题描述】:

这主要是一个设计/效率问题,但我想看看在 neo4j 中是否有更好的方法来处理这个问题,而不是在 sql db 中处理它。

现在我有 2 个模型 - userevent。我也有userevent之间的关系,表示他们将参加活动。我想找出代表活动管理员的最佳方式。换句话说,我希望能够查询由用户管理的事件。

一种方法是在用户和event 之间创建一个名为admin_of 的新关系。另一种方法是创建参与关系的管理属性。类似admin: true

admin_of 查询看起来很简单,但会向数据库添加另一个关系。以后也可以处理多管理员。

我认为后一种方式可以通过以下方式查询:(来自文档)EnrolledIn.where(since: 2002) 所以我的搜索将包括admin: true。但是我不确定如何链接它,因为我希望它只是朋友活动。其他where 查询通常基于节点而不是关系的属性。

后一种方法似乎是首选方法,但是查询它的正确方法是什么?还是第一种方法更简单,即使它增加了额外的关系?

更新: 我想出了这样的东西

result = Event.query_as(:event).match("event<-[invite: INVITED]-(user: User)<-[:FRIENDS_WITH]-(user)").where(invite: {admin: /true/}).pluck(:event)

基于详细查询

https://github.com/neo4jrb/neo4j/wiki/Search-and-Match

更新 2

我现在有这个,但没有得到匹配。开始剖析我的查询出了什么问题的最佳方法是什么?

current_user.friends.events.query_as(:event).match("event<-[invite]-(user: User)<-[friends_with]-(user)").where(invite: {admin: true}, event: {detail: 'property'}).pluck(:event)

我的用户模型有

has_many :both, :events, model_class: 'Event', rel_class: 'Invite'

我的事件模型有

has_many :both, :users, model_class: 'User', rel_class: 'Invite'

我的邀请模型有

  from_class Event
  to_class   User
  type 'invited'

【问题讨论】:

  • 要开始拆分查询,请从控制台中的日志中复制 Cypher 并粘贴到 Neo4j 网络浏览器 localhost:7474。您需要用字符串/整数替换参数并添加一个返回值。在你得到某种回应之前,仍然会抽出部分内容。
  • 另外,如果您的密码查询,请修复一些问题。给它一个 rel 类型,不要只使用标识符。 current_user.friends.events.query_as(:event).match("event<-[invite:INVITED_BY]-(user: User)<-[friends_with:FRIENDS_WITH]-(user)").where(invite: {admin: true}, event: {detail: 'property'}).pluck(:event) 什么的。
  • 那里没有类型会伤害查询吗?例如它获得的效率是多少?我不完全确定用字符串/整数替换参数是什么意思。其中一个查询是MATCH (user0:User), (node2:User), user0-[rel0:friends_with]-(node2:User), (event:Event), node2-[rel1:invited@ 987654346@Event), event<-[invite:INVITED]-(user: User)<-[friends_with:FRIENDS_WITH]-(user: User) WHERE ID(user0) = {ID_user0} AND invite.admin = {invite_admin} RETURN event | {:ID_user0=>0, :invite_admin=>true}
  • 我删掉了一堆没有用..MATCH (user1:User), (user2:User), (event:Event), event<-[invite:INVITED]-(user: User)<-[friends_with:FRIENDS_WITH]-(user: User) WHERE user1.id = 133342 AND invite.admin = true RETURN event
  • user1的ID属性真的是133342吗?如果你这样做MATCH (u:User { id: 133342 }) return u,它会回来吗?在那场比赛中,用户 1 和用户 2 的角色是什么?它们不会出现在该路径中。

标签: ruby-on-rails neo4j relationship neo4j.rb


【解决方案1】:

这是我想了很多的事情,并且本身就值得写一篇博文或截屏。我有我的最佳实践,但不会说这是最好的方法。可能有一些我没有考虑过的事情。不过,这就是我正在使用的东西。

您指出了每个关系的主要优点和缺点:额外的关系使遍历变得容易,并且添加新的管理员也很容易,但是维护两组本质上做同样事情的关系是完全拖累的。对我来说,这甚至与数据库中的额外垃圾无关,而是关于管理这些额外垃圾的所有额外工作。

一般来说,当我可以利用现有关系时,我会尽量避免为管理信息等内容创建额外的关系。我已经确定了两种做法:

  • 首先,您可以通过跟踪对象的路径来获得基本的“有权访问/无权访问”,如更新中所示。如果您想将范围缩小到仅限朋友的活动,请执行以下操作:

    friend.events.query_as(:event).match.all_the_rest_of_your_chain

通过为朋友开始,您将只返回与他们相关的事件。现在,如果您只想要他们拥有的事件...

  • 您可以在关系中使用整数属性,我通常调用我的score,来表示该用户对它的访问级别。整数很酷,因为您可以设置评分约定,0 是无权限,50 是编辑器,99 是管理员——类似这样——然后说“where rel.score > {admin_score}”,你只会得到那些他们具有正确访问级别或更高级别的关系。应该是这样的……

    friend.events(:e, :rel).where("rel.score > {privileged_score}").params(privileged_score: 0).continue_your_chain

请注意,我们必须使用字符串并设置自己的参数,因为 QueryProxy 中的 where 将针对最新的节点,我们不能这样做 .where(rel: { score: privileged_score })。 (顺便说一句,我计划尽快添加一个rel_where 方法来处理这个问题。)

无论如何,这只会返回访问级别高于默认值的朋友的事件,这意味着某种高级安全级别。

我会从那里开始。当您遇到更高级的授权问题时,例如“匹配用户拥有事件或拥有事件发生地点的事件,包括特权信息,但有多少特权信息取决于他们拥有哪些项目......和如果两者兼而有之呢?”还有一些考虑因素,但我们可以再谈。 ;-)

您可能还想阅读https://github.com/neo4jrb/neo4j/wiki/Search-and-Scope 的范围。在当前版本中它有点粗糙和错误,但布赖恩有 an open PR 进行更新,使它变得更好。您将能够编写自定义方法:

def privileged_events(score = 0
  events(:e, :rel).where("rel.score = {rel_score}").params(rel_score: score) 
end

然后执行user.privileged_events.more_query_chain_methods 之类的操作,以使查询片段更可重用。我们有一个规范要修复,它只是一个双精度的问题,它将被合并到主控中。我们应该会在几天内发布 4.0 候选版本(如果我们甚至认为需要 RC)。

还有一件事......

另外需要考虑的是,您还可以执行两个查询以仅返回特权信息:返回用户应该看到的所有事件,然后根据视图中的关系进行过滤。

<%= @events.each do |event| %>
  <% if @event.users(:u, :rel).where("rel.score = {admin_score}").params(admin_score: 99).include?(current_user) %>
    # do stuff
  <% end %>
<% end %>

include? 调用将在服务器端处理并返回一个布尔值,它的开销并不大。

我认为它并不理想——它的效率肯定较低——但它更容易构建。你总是可以重构;见鬼,你应该期望无论如何你都需要重构。

【讨论】:

  • 要消化的东西太多了,哈哈。为了更简化的目的,使用您的示例,我可以执行current_user.friends.events.query_as(:event).match("event&lt;-[invite: INVITED]-(user: User)&lt;-[:FRIENDS_WITH]-(user)").where(invite: {admin: /true/}, event: {property: /something/} ).pluck(:event) 之类的操作。我不能马上打电话给friend.events,因为朋友是通过用户识别的,朋友也是用户。
  • 我在我的 Rails 控制台中注意到,当我执行此查询时,我得到 =~true 以匹配 where=~ 是怎么回事?在查询中需要/ 而不是使用引号?
  • 不要使用/true/。是在文档中吗?这会进行正则表达式搜索。 /something/ 是一个 Ruby 正则表达式,Cypher 使用 =~ 来表示它,所以我们为您转换它。只需where(admin: true)
  • 是的,它在文档中。开始认为这是一个特殊的密码。我可能会写一个注释,说明正则表达式。我喜欢在用户权限方面具有灵活性的想法,但甚至无法让基本查询正常工作。见上文更新
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-17
相关资源
最近更新 更多