Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 不确定如何使用Mongoid中的标志建模多对多关系_Ruby On Rails_Mongodb_Mongoid - Fatal编程技术网

Ruby on rails 不确定如何使用Mongoid中的标志建模多对多关系

Ruby on rails 不确定如何使用Mongoid中的标志建模多对多关系,ruby-on-rails,mongodb,mongoid,Ruby On Rails,Mongodb,Mongoid,我有两个实体,项目和用户。它们在Rails中使用Mongoid和两个文档实例(User和Project)进行建模 在这个系统中,一个用户可以创建一个项目,但是许多用户可以跟踪许多项目。例如,作为用户\u id 1,我创建了项目\u id 1。但是用户id 10、11、40和60都遵循项目id 1。我需要表示用户和项目之间的多对多关系,并将特定的用户id表示为项目的创建者,以分配给他编辑权限 实际上,当用户登录时,他需要能够看到他正在关注的所有项目,包括他创建的任何项目,以及其他用户创建的其他项目

我有两个实体,项目和用户。它们在Rails中使用Mongoid和两个文档实例(User和Project)进行建模

在这个系统中,一个用户可以创建一个项目,但是许多用户可以跟踪许多项目。例如,作为用户\u id 1,我创建了项目\u id 1。但是用户id 10、11、40和60都遵循项目id 1。我需要表示用户和项目之间的多对多关系,并将特定的用户id表示为项目的创建者,以分配给他编辑权限

实际上,当用户登录时,他需要能够看到他正在关注的所有项目,包括他创建的任何项目,以及其他用户创建的其他项目。他的特殊创造者身份根本不会影响这份名单。当用户查看特定项目时,他需要能够查看项目的所有用户,如果他是创建者,他可以添加新的关注者并删除现有的关注者

在RDBMS中,我将用表
users
projects
users\u projects
join表来表示这一点,该表的标志为
is\u creator
。这将很容易让我选择用户可以看到哪些项目,哪些用户是项目的追随者,包括哪些用户是项目的创建者

Mongoid支持多对多关系,但与RDBMS不同,我无法在关系上设置标志。相反,我想我将在
项目
文档中添加一个
创建者
字段,该字段将包含一个指向用户文档上
\u id
字段的链接

用户->项目关系可能如下所示

class User
  has_and_belongs_to_many :projects
end

class Project
  has_and_belongs_to_many: users
end
但是我不知道如何映射creator->created\u projects之间的关系。我相信我可以在
Project
中引用用户创建者,比如
属于:creator,:class\u name=>“user”
,但我不确定如何设置另一方


如何在Mongoid中对这些关系进行最佳建模?

创建一个嵌入式文档,其中包含所有关注者及其用户id和用户名,这样您就不必查询关注者的用户名

好处:

  • 没有一个查询可以查找项目的跟随者
  • 只有一个查询可以查找用户的后续项目
缺点是:

  • 如果一个用户更改了他的名字,你必须更新他的所有“followships”,但更新频率如何 与查找后续项目的频率相比,您是否更改了名称;)

  • 如果每个项目有数千名追随者,则可能达到16mb的文档限制

user.rb

class User
  # projects this user owns
  has_many :projects

  def followed_projects
    Project.where('followers.user_id' => self.id)
  end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {'followers.user_id' => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  embeds_many :followers

  # add an index because we're going to query on this
  index 'followers.user_id'

  # adds a follower
  # maybe you want to add some validations, preventing duplicate followers
  def add_follower!(user_obj)
    self.followers.create({
      :user       => user_obj,
      :username   => user_obj.username
    })
  end

  def remove_follower!(user_obj)
    self.followers.destroy_all(:conditions => {:user_id => user_obj.id})
  end

end
class Follower
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :project

  # reference to the real user
  belongs_to :user

  # cache the username
  field :username, :type => String
end
class User
  # projects this user owns
  has_many :projects
  has_many :followed_projects, 
           :class_name => 'Project', 
           :foreign_key => :follower_ids

  # Uncomment if the relation does not work
  #def followed_projects
  #  Project.where(:follower_ids => self.id)
  #end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {:follower_ids => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  field :follower_ids, :type => Array

  # adds a follower
  def add_follower!(user_obj)
    # adds a user uniquely to the follower_ids array
    self.add_to_set(:follower_ids, user_obj.id)
  end

  def remove_follower!(user_obj)
    # remove the user
    self.pull(:follower_ids, user_obj.id)
  end
end
project.rb

class User
  # projects this user owns
  has_many :projects

  def followed_projects
    Project.where('followers.user_id' => self.id)
  end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {'followers.user_id' => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  embeds_many :followers

  # add an index because we're going to query on this
  index 'followers.user_id'

  # adds a follower
  # maybe you want to add some validations, preventing duplicate followers
  def add_follower!(user_obj)
    self.followers.create({
      :user       => user_obj,
      :username   => user_obj.username
    })
  end

  def remove_follower!(user_obj)
    self.followers.destroy_all(:conditions => {:user_id => user_obj.id})
  end

end
class Follower
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :project

  # reference to the real user
  belongs_to :user

  # cache the username
  field :username, :type => String
end
class User
  # projects this user owns
  has_many :projects
  has_many :followed_projects, 
           :class_name => 'Project', 
           :foreign_key => :follower_ids

  # Uncomment if the relation does not work
  #def followed_projects
  #  Project.where(:follower_ids => self.id)
  #end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {:follower_ids => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  field :follower_ids, :type => Array

  # adds a follower
  def add_follower!(user_obj)
    # adds a user uniquely to the follower_ids array
    self.add_to_set(:follower_ids, user_obj.id)
  end

  def remove_follower!(user_obj)
    # remove the user
    self.pull(:follower_ids, user_obj.id)
  end
end
follower.rb

class User
  # projects this user owns
  has_many :projects

  def followed_projects
    Project.where('followers.user_id' => self.id)
  end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {'followers.user_id' => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  embeds_many :followers

  # add an index because we're going to query on this
  index 'followers.user_id'

  # adds a follower
  # maybe you want to add some validations, preventing duplicate followers
  def add_follower!(user_obj)
    self.followers.create({
      :user       => user_obj,
      :username   => user_obj.username
    })
  end

  def remove_follower!(user_obj)
    self.followers.destroy_all(:conditions => {:user_id => user_obj.id})
  end

end
class Follower
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :project

  # reference to the real user
  belongs_to :user

  # cache the username
  field :username, :type => String
end
class User
  # projects this user owns
  has_many :projects
  has_many :followed_projects, 
           :class_name => 'Project', 
           :foreign_key => :follower_ids

  # Uncomment if the relation does not work
  #def followed_projects
  #  Project.where(:follower_ids => self.id)
  #end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {:follower_ids => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  field :follower_ids, :type => Array

  # adds a follower
  def add_follower!(user_obj)
    # adds a user uniquely to the follower_ids array
    self.add_to_set(:follower_ids, user_obj.id)
  end

  def remove_follower!(user_obj)
    # remove the user
    self.pull(:follower_ids, user_obj.id)
  end
end
如何使用它:

@project    = Project.first
@some_user  = User.last

@project.add_follower!(@some_user)

@some_user.followed_projects
@some_user.related_projects

@project.followers.each do |c_follower|
  puts "I'm #{c_follower.username} and I'm following this project!"
end

@all_follower_user_ids = @project.followers.map{|c| c.user_id}

# find a specific follower by user_id 
@some_follower = @project.followers.where(:user_id => 1234)
# find a specific follower by username
@some_follower = @project.followers.where(:username => 'The Dude')

@project.remove_follower!(@some_user)
@project    = Project.first
@some_user  = User.last

@project.add_follower!(@some_user)

@some_user.followed_projects
@some_user.related_projects

# create hash like @ids_to_user[user_id] = user
@ids_to_users = User.find(@project.follower_ids).inject({}) {|hsh, c_user| hsh[c_user.id] = c_user; hsh}

@project.followers.each do |c_follower|
  puts "I'm #{@ids_to_users[c_follower].username} and I'm following this project!"
end

@project.remove_follower!(@some_user)

PS:如果您想要一个更简单的解决方案,您可以在项目中嵌入一个ObjectID数组(用户ID),并使用原子更新
$addToSet
$pullAll
来添加/删除跟随者。但是您需要一个额外的查询,如
User.where(:User\u id.in=>@project.follower\u id)
(假设数组名为
follower\u id
),以获取所有用户及其姓名;)

第二个版本使用更少的空间,但需要额外的查询来获取用户名等用户详细信息。一个对象ID有12个字节,最大文档大小为16mb,因此阵列可以容纳约130万个用户ID(理论上!)

给你:

user.rb

class User
  # projects this user owns
  has_many :projects

  def followed_projects
    Project.where('followers.user_id' => self.id)
  end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {'followers.user_id' => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  embeds_many :followers

  # add an index because we're going to query on this
  index 'followers.user_id'

  # adds a follower
  # maybe you want to add some validations, preventing duplicate followers
  def add_follower!(user_obj)
    self.followers.create({
      :user       => user_obj,
      :username   => user_obj.username
    })
  end

  def remove_follower!(user_obj)
    self.followers.destroy_all(:conditions => {:user_id => user_obj.id})
  end

end
class Follower
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :project

  # reference to the real user
  belongs_to :user

  # cache the username
  field :username, :type => String
end
class User
  # projects this user owns
  has_many :projects
  has_many :followed_projects, 
           :class_name => 'Project', 
           :foreign_key => :follower_ids

  # Uncomment if the relation does not work
  #def followed_projects
  #  Project.where(:follower_ids => self.id)
  #end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {:follower_ids => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  field :follower_ids, :type => Array

  # adds a follower
  def add_follower!(user_obj)
    # adds a user uniquely to the follower_ids array
    self.add_to_set(:follower_ids, user_obj.id)
  end

  def remove_follower!(user_obj)
    # remove the user
    self.pull(:follower_ids, user_obj.id)
  end
end
project.rb

class User
  # projects this user owns
  has_many :projects

  def followed_projects
    Project.where('followers.user_id' => self.id)
  end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {'followers.user_id' => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  embeds_many :followers

  # add an index because we're going to query on this
  index 'followers.user_id'

  # adds a follower
  # maybe you want to add some validations, preventing duplicate followers
  def add_follower!(user_obj)
    self.followers.create({
      :user       => user_obj,
      :username   => user_obj.username
    })
  end

  def remove_follower!(user_obj)
    self.followers.destroy_all(:conditions => {:user_id => user_obj.id})
  end

end
class Follower
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :project

  # reference to the real user
  belongs_to :user

  # cache the username
  field :username, :type => String
end
class User
  # projects this user owns
  has_many :projects
  has_many :followed_projects, 
           :class_name => 'Project', 
           :foreign_key => :follower_ids

  # Uncomment if the relation does not work
  #def followed_projects
  #  Project.where(:follower_ids => self.id)
  #end

  # get projects that this user has created and projects he is following
  def related_projects
    Project.any_of({:user_id  => self.id}, {:follower_ids => self.id})
  end
end
class Project
  # creator
  belongs_to :user

  field :follower_ids, :type => Array

  # adds a follower
  def add_follower!(user_obj)
    # adds a user uniquely to the follower_ids array
    self.add_to_set(:follower_ids, user_obj.id)
  end

  def remove_follower!(user_obj)
    # remove the user
    self.pull(:follower_ids, user_obj.id)
  end
end
如何使用它:

@project    = Project.first
@some_user  = User.last

@project.add_follower!(@some_user)

@some_user.followed_projects
@some_user.related_projects

@project.followers.each do |c_follower|
  puts "I'm #{c_follower.username} and I'm following this project!"
end

@all_follower_user_ids = @project.followers.map{|c| c.user_id}

# find a specific follower by user_id 
@some_follower = @project.followers.where(:user_id => 1234)
# find a specific follower by username
@some_follower = @project.followers.where(:username => 'The Dude')

@project.remove_follower!(@some_user)
@project    = Project.first
@some_user  = User.last

@project.add_follower!(@some_user)

@some_user.followed_projects
@some_user.related_projects

# create hash like @ids_to_user[user_id] = user
@ids_to_users = User.find(@project.follower_ids).inject({}) {|hsh, c_user| hsh[c_user.id] = c_user; hsh}

@project.followers.each do |c_follower|
  puts "I'm #{@ids_to_users[c_follower].username} and I'm following this project!"
end

@project.remove_follower!(@some_user)

非常感谢。这正是我想要的。问题是,我已经尝试使用您的替代建议来实现这一点,即在项目文档中存储用户id对象,但在定义项目和用户之间的关系时遇到了一个难题。你介意也贴一个解决方案的例子吗?