【问题标题】:Mongoid push new embedded document in a single queryMongoid 在单个查询中推送新的嵌入文档
【发布时间】:2015-04-27 04:08:35
【问题描述】:

我们使用 mongoid 来存储用户分数:

class UserScore
  include Mongoid::Document

  field :user_id, type: Integer
  field :points,  type: Integer, default: 0
  embeds_many :activities
end

我们通过将用户的活动收集到称为活动的嵌入式文档中来跟踪它们。随着活动数量的增加,如果 mongoid 将加载所有嵌入文档,访问 user.user_score 的时间也会增加。如果我们添加一个新活动,它总是会导致两个查询:

UserScore.where( user_id: user.id ).first.activities << Activity.new(values)

一个查询用于查找 UserScores,一个查询用于推送。

MOPED: 127.0.0.1:27017 QUERY        database=development collection=user_scores selector={"$query"=>{"user_id"=>121920}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil 
(192.1866ms)
MOPED: 127.0.0.1:27017 UPDATE       database=development collection=user_scores selector={"_id"=>"53cfe22869d256929d000139"} update={"$push"=>{"activities"=>{"_id"=>"54ed824d4c5c34f157000011", "points"=>50, "created_at"=>2015-02-25 08:05:33 UTC}}} flags=[] 
(0.5269ms)

find-query 并不是必需的,因为我们也可以像这样使用 moped 推送一个新的嵌入文档:

Mongoid::Sessions.default[:user_scores].find(user_id: user.id).update('$push' => {'activities' => values)})

MOPED: 127.0.0.1:27017 UPDATE       database=development collection=user_scores selector={:user_id=>125721} update={"$push"=>{"activities"=>{:points=>50, "_id"=>"54ed80224c5c34f157000007", :created_at=>2015-02-25 07:56:18 UTC}}} flags=[] 
(0.5438ms)

有没有办法在 mongoid 中实现这一点? 我们想要使用 mongoid 的原因是我们想要将新的活动作为一个 ruby​​ 对象来处理。同样通过推送这样的值,活动文档缺少我们必须在应用程序中创建的 _id 和 created_at 字段,这会导致更丑陋的代码。

我们使用 mongoid 3.1.6。是否有可能在以后的版本中添加或将添加一种延迟加载?

更新:

我们模拟用户和用户分数之间的关系,因为用户存储在 mysql 数据库中:

class User
  def user_score
    UserScore.where(user_id: self.id).first
  end
end

所以我们不能像这样使用关系

user.user_score << Activity.new(values)

没有相同的结果。

【问题讨论】:

    标签: ruby mongodb mongoid


    【解决方案1】:

    你试过这个吗:

    a = Activity.new(values)
    a.user_score = user.user_score
    a.save
    

    这可能需要您编写已存储数据的 has_manybelongs_to 关系:

    class UserScore
        belongs_to :user
    end
    
    class User
        has_many :user_scores
    end
    

    【讨论】:

    • 不幸的是,我们模拟了 user 和 user_score 之间的关系,因为 user 存储在 mysql 中。我更新了问题。
    • 试试等价的,而不是user.user_score,做a.user_score = &lt;your_mysql_find_query&gt;
    【解决方案2】:

    经过更多研究,似乎没有替代我在问题中描述的方法。 Mongoid 总是用嵌入的文档加载整个文档。如果使用only(),则无法操作文档。

    我还注意到,如果您有超过几千个嵌入文档,则推入数组会变得低效。这两个问题的解决方案是将嵌入的文档移动到单独的集合中。

    【讨论】:

      猜你喜欢
      • 2011-04-26
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-11
      相关资源
      最近更新 更多