新手问题 记录删除的处理方法

joezhang · January 23, 2014 · Last by joezhang replied at January 25, 2014 · 3452 hits

Model:

class User include Mongoid::Document field :name, type: String has_many :topics, dependent: :destory end

class Topic include Mongoid::Document belongs_to :user field :title, type: String field :like_ids, type => Array. :default => [] end

删除 user,那么 user 所创建的 topics 全部删除,这没什么问题。 但是在其他 user 创建的 topic 中,like_ids 保存有被删除 user 的 id,应该怎么处理比较方便?

目前我能想出的苯的方法是删除 user 前,检索一遍所有其他 user 的 like_ids Array 中是否有被删除的 user.id,调用 pull () 在 like_ids Array 中去掉被删除的 user.id。但是如果日后 user 和 topic 记录多了之后,就会比较影响性能。

请指点一下,谢谢。

在需要读取属性的地方处理无效 ids

@dddd1919 谢谢你的建议,比我原来光想着删除的方法好!

#2 楼 @joezhang 删除删一次就行了,读取时处理每次读都要处理一遍,怎么会更好呢?

这个操作 Mongodb 可以批量执行啊。update_all

丢到 delayed jobs 里面去删?没想到什么特别好的办法

不要过早考虑性能问题,大部分项目其实都看不到性能问题出现就死了。

感觉有点奇怪,好像是设计上有问题。topics 和 喜欢他的用户应该是多对多

#3 楼 @blacktulip 我最后采取的方式是在需要读取 ids 的地方做判断,如果是无效 ids 就不显示,同时在 Array 中移出。

#6 楼 @kgen 谢谢,只是自己的小项目,想知道有没有好的设计方法,避免以后实际项目中犯同样的错误。

#7 楼 @Yujing_Z 谢谢,我是仿照 Ruby-China 论坛的设计,详细请查看 Ruby-China 论坛源码的 Topic model.

# 回复过的人的 ids 列表
field :follower_ids, :type => Array, :default => []

#9 楼 @joezhang 人不都说了你这设计问题,NN 有你这样设计的么

#10 楼 @joezhang 噢,ruby-china 源码我确实没有仔细看过,可能有性能考虑什么的。我说的是普通的数据库设计原则,你可以看这里,http://mongoid.org/en/mongoid/docs/relations.html#has_and_belongs_to_many 这样你就可以topic.liked_users user.liked_topics 随便找了

#10 楼 @joezhang 你这个确实参考错例子了,ruby-china 和你的需求不同,他们的设计有他们的道理。Topic 关心 followers,但是还有个 model 叫 reply,user 找的是他的 replies

#13 楼 @Yujing_Z谢谢,我前面举的例子是省略了的,其实我的设计是 like user 同样需要 reply something 的,你上面提到的多对多设计我也考虑了,不过觉得再加 reply 的时候不好处理,所以才想着仿照 ruby-china 的设计,呵呵,想着是大牛们的设计,肯定有他们的道理。大牛们能出来解答一下就好了。

我想大概就是因为:Many to many relations require usually double the amount of hits to the database to keep both sides of the relation in sync, since keys are stored on both sides. Due to this they are slower and should be used with caution.

#14 楼 @joezhang 你这个说法不对。ruby-china 没有 找一个用户关注的所有的帖子 这个功能,所以可以这样设计。而很明显你不一样,你有找到一个帖子所有 liked_user 的需求。所以你这样设计,想来想去也没有什么特别好的办法,那是因为根本没有这样的办法。只能每次都遍历,这样跟你设计成 N-to-N 来比,真的就有性能优势?我看未必,还带来了代码复杂度

而 reply 完全又是一个独立的功能,跟这个完全没有关系,很好处理

used with caution 不代表不能用,NN 是很常见的需求,确实会慢一点,但是就跟 kgen 说的一样,这么早的阶段担心个啥,怎么让程序员方便怎么来。加快开发速度


不过我当然不反对你这样每次都遍历一遍的做法,个人有个人追求

#15 楼 @Yujing_Z谢谢,“ruby-china 没有 找一个用户关注的所有的帖子 这个功能,所以可以这样设计。而很明显你不一样,你有找到一个帖子所有 liked_user 的需求”,这个分析很正确,赞一个!

决定接受你的建议,重新设计成 N-to-N 模式。

#7 楼 @Yujing_Z 其实就算有查找用户关注的所有帖子功能,也可能是在 Topic 单边存 like_ids 更快。

以前做过性能测试,不过测试脚本不小心删了,仅供参考,最好自己试一试 http://codecampo.com/topics/168

清除 User 的 like 数据我在 4 楼已经说了

Topic.where(like_ids: user.id).pull(:like_ids: user.id)

AND,不要忘了 Mongodb 可以对数组字段建索引。

#17 楼 @Rei 在 user_controller.rb 中做以下处理,like_ids Array 中的 user.id 还是没有被删除。

def destroy
    Topic.where(like_ids: params[:id]).pull(like_ids: params[:id])
    User.find(params[:id]).destroy
    flash[:success] = "用户成功删除!"
    redirect_to users_path
  end

#19 楼 @joezhang params[:id] 类型应该是字符,可能跟存的 id 不同。

#20 楼 @Rei正确,改成以下就通过了。谢谢了,这下不用重新设计成 N-to-N 模式了。

def destroy
    @user = User.find(params[:id])
    Topic.where(like_ids: @user.id).pull(like_ids: @user.id)
    User.find(params[:id]).destroy
    flash[:success] = "用户成功删除!"
    redirect_to users_path
  end
You need to Sign in before reply, if you don't have an account, please Sign up first.