gpt4 book ai didi

ruby-on-rails - MongoDB 对 HABTM 关系(Mongoid、RoR)进行条件聚合查询?

转载 作者:行者123 更新时间:2023-12-02 03:11:33 24 4
gpt4 key购买 nike

Rails 4.2.5 , Mongoid 5.1.0

我有三个模型 - Mailbox , Communication ,和Message .

mailbox.rb

class Mailbox
include Mongoid::Document
belongs_to :user
has_many :communications
end

communication.rb

class Communication
include Mongoid::Document
include Mongoid::Timestamps
include AASM

belongs_to :mailbox
has_and_belongs_to_many :messages, autosave: true

field :read_at, type: DateTime
field :box, type: String
field :touched_at, type: DateTime
field :import_thread_id, type: Integer
scope :inbox, -> { where(:box => 'inbox') }
end

message.rb

class Message
include Mongoid::Document
include Mongoid::Timestamps

attr_accessor :communication_id

has_and_belongs_to_many :communications, autosave: true
belongs_to :from_user, class_name: 'User'
belongs_to :to_user, class_name: 'User'

field :subject, type: String
field :body, type: String
field :sent_at, type: DateTime
end

我正在使用身份验证 gem devise ,它可以访问 current_user helper,它指向当前登录的用户。

我已经为满足以下条件的 Controller 构建了一个查询:获取current_usermailbox ,其communication的过滤条件为 box场,其中 box == 'inbox' 。它的构造如下(并且正在运行):

current_user.mailbox.communications.where(:box => 'inbox')

当我尝试基于此查询进行构建时,出现了问题。我希望链接查询,以便我只获得 messages谁的last消息不是来自current_user 。我知道 .last 方法,它返回最新的记录。我提出了以下查询,但无法理解需要调整哪些内容才能使其工作:

current_user.mailbox.communications.where(:box => 'inbox').where(:messages.last.from_user => {'$ne' => current_user})

该查询产生以下结果: undefined method 'from_user' for #<Origin::Key:0x007fd2295ff6d8>

我目前能够通过执行以下操作来完成此任务,我知道这样做效率非常低,并且希望立即更改:

mb = current_user.mailbox.communications.inbox

comms = mb.reject {|c| c.messages.last.from_user == current_user}

我希望将此逻辑从 ruby​​ 移至实际的数据库查询。预先感谢任何在这方面为我提供帮助的人,如果有更多信息对我有帮助,请告诉我。

最佳答案

好吧,这里发生的事情有点困惑,并且与 Mongoid 在进行关联时实际上能够有多聪明有关。

特别是在两个关联之间“交叉”时如何构造查询。

对于您的第一个查询:

current_user.mailbox.communications.where(:box => 'inbox')

这对于 mongoid 来说很酷,因为它实际上只是脱糖为真正的 2 个数据库调用:

  1. 获取用户当前邮箱
  2. Mongoid 直接针对通信集合构建一个条件,其中的 where 语句表示:使用第 1 项中的邮箱 ID,并过滤到 box = inbox。

现在,当我们处理您的下一个查询时,

current_user.mailbox.communications.where(:box => 'inbox').where(:messages.last.from_user => {'$ne' => current_user})

是 Mongoid 开始感到困惑的时候。

这是主要问题:当您使用“where”时,您正在查询您所在的集合。您不会交叉关联

where(:messages.last.from_user => {'$ne' => current_user}) 实际上所做的是检查消息关联。 Mongoid 实际上做的是在通信文档中搜索具有类似于以下 JSON 路径的属性:communication['messages']['last']['from_user']。

现在您知道原因了,您可以得到您想要的东西,但是这需要比同等的 ActiveRecord 工作付出更多的努力。

以下是您获得所需内容的更多方法:

user_id = current_user.id
communication_ids = current_user.mailbox.communications.where(:box => 'inbox').pluck(:_id)
# We're going to need to work around the fact there is no 'group by' in
# Mongoid, so there's really no way to get the 'last' entry in a set
messages_for_communications = Messages.where(:communications_ids => {"$in" => communications_ids}).pluck(
[:_id, :communications_ids, :from_user_id, :sent_at]
)
# Now that we've got a hash, we need to expand it per-communication,
# And we will throw out communications that don't involve the user
messages_with_communication_ids = messages_for_communications.flat_map do |mesg|
message_set = []
mesg["communications_ids"].each do |c_id|
if communication_ids.include?(c_id)
message_set << ({:id => mesg["_id"],
:communication_id => c_id,
:from_user => mesg["from_user_id"],
:sent_at => mesg["sent_at"]})
end
message_set
end
# Group by communication_id
grouped_messages = messages_with_communication_ids.group_by { |msg| mesg[:communication_id] }
communications_and_message_ids = {}
grouped_messages.each_pair do |k,v|
sorted_messages = v.sort_by { |msg| msg[:sent_at] }
if sorted_messages.last[:from_user] != user_id
communications_and_message_ids[k] = sorted_messages.last[:id]
end
end
# This is now a hash of {:communication_id => :last_message_id}
communications_and_message_ids

我不确定我的代码是否 100%(您可能需要检查文档中的字段名称以确保我正在搜索正确的字段名称),但我认为您已经了解了一般模式。

关于ruby-on-rails - MongoDB 对 HABTM 关系(Mongoid、RoR)进行条件聚合查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35466893/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com