Mongoid 在单个查询中推送新的嵌入式文档
Mongoid push new embedded document in a single query
我们使用 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 也会增加。如果我们添加一个新的 activity,它总是会产生两个查询:
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)
查找查询并不是必需的,因为我们也可以像这样使用助力车推送新的嵌入式文档:
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 的原因是我们想要将新的 activity 作为一个 ruby 对象来处理。此外,通过像这样推送值,activity 文档缺少我们必须在应用程序中创建的 _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)
没有相同的结果。
你试过这个吗:
a = Activity.new(values)
a.user_score = user.user_score
a.save
这可能需要您编写您已经存储数据的 has_many
和 belongs_to
关系:
class UserScore
belongs_to :user
end
class User
has_many :user_scores
end
经过更多研究后,似乎没有其他方法可以替代我在问题中描述的方法。 Mongoid 总是加载带有嵌入文档的整个文档。如果使用only(),则无法操作文档。
我还注意到,如果您有几千个嵌入式文档,则推入数组会变得效率低下。这两个问题的解决方案是将嵌入的文档移动到一个单独的集合中。
我们使用 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 也会增加。如果我们添加一个新的 activity,它总是会产生两个查询:
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)
查找查询并不是必需的,因为我们也可以像这样使用助力车推送新的嵌入式文档:
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 的原因是我们想要将新的 activity 作为一个 ruby 对象来处理。此外,通过像这样推送值,activity 文档缺少我们必须在应用程序中创建的 _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)
没有相同的结果。
你试过这个吗:
a = Activity.new(values)
a.user_score = user.user_score
a.save
这可能需要您编写您已经存储数据的 has_many
和 belongs_to
关系:
class UserScore
belongs_to :user
end
class User
has_many :user_scores
end
经过更多研究后,似乎没有其他方法可以替代我在问题中描述的方法。 Mongoid 总是加载带有嵌入文档的整个文档。如果使用only(),则无法操作文档。
我还注意到,如果您有几千个嵌入式文档,则推入数组会变得效率低下。这两个问题的解决方案是将嵌入的文档移动到一个单独的集合中。