MongoDB中嵌套文档的关联查询

huangapple go评论65阅读模式
英文:

MongoID join on embedded documents

问题

We have a Shipment document with an embedded ShipmentEvent document as in...

class Shipment
  include Mongoid::Document
  embeds_many :shipment_events
end

class ShipmentEvent
  include Mongoid::Document
  embedded_in :shipment
end

What we need to get is a join containing shipments and their latest shipment_event based on a :event_at field.

Example data (simplified with just one shipment):

[
  {
    "_id" => BSON::ObjectId('1'),
    "shipment_events" => [
      {
        "_id" => BSON::ObjectId('2'),
        "event_at" => 2022-04-09 15:00:00 UTC
      },
      {
        "_id" => BSON::ObjectId('3'),
        "event_at" => 2022-04-09 18:00:00 UTC
      }
    ]
  }
]

The result expected should contain the shipment and only the second (latest by :event_at) shipment_event. Something like...

[
  {
    "_id" => BSON::ObjectId('1'),
    "_event_id" => BSON::ObjectId('3'),
    "event_at" => 2022-04-09 18:00:00 UTC
  }
]

I know join queries are not possible with MongoId and we will need to use aggregation I guess. Any ideas will be appreciated.

Thank you.

英文:

We have a Shipment document with an embedded ShipmentEvent document as in...

class Shipment
  include Mongoid::Document
  embeds_many :shipment_events
end

class ShipmentEvent
  include Mongoid::Document
  embedded_in :shipment
end

What we need to get is a join containing shipments and theirs latest shipment_event based on a :event_at field.

Example data (simplified with just one shipment):

[
  {
    "_id" => BSON::ObjectId('1'),
    "shipment_events" => [
      {
        "_id" => BSON::ObjectId('2'),
        "event_at" => 2022-04-09 15:00:00 UTC
      },
      {
        "_id" => BSON::ObjectId('3'),
        "event_at" => 2022-04-09 18:00:00 UTC
      }
    ]
  }
]

The result expected should contain the shipment and only the second (latest by :event_at) shipment_event. Something like...

[
  {
    "_id" => BSON::ObjectId('1'),
    "_event_id" => BSON::ObjectId('3'),
    "event_at" => 2022-04-09 18:00:00 UTC
  }
]

I know join queries are not possible with MongoId and we will need to use aggregation I guess. Any ideas will be appreciated.

Thank you.

答案1

得分: 0

以下是翻译好的内容:

你可以这样做:

    unwind = { "$unwind" => "$shipment_events" }
    sort = {
      "$sort" => {
        "_id" => 1, "shipment_events.event_at" => -1
      }
    }
    group = {
      "$group" => {
        "_id" => "$_id",
        "event_id" => {
          "$first" => "$$ROOT.shipment_events._id"
        },
        "event_at" => {
          "$first" => "$$ROOT.shipment_events.event_at"
        }
      }
    }
    
    Shipment.collection.aggregate([unwind, sort, group])

请在下方找到示例 playground 链接。
https://mongoplayground.net/p/oLTG-18aIDm
英文:

You can do it this way:

unwind = { "$unwind" => "$shipment_events" }
sort = {
  "$sort" => {
    "_id" => 1, "shipment_events.event_at" => -1
  }
}
group = {
  "$group" => {
    "_id" => "$_id",
    "event_id" => {
      "$first" => "$$ROOT.shipment_events._id"
    },
    "event_at" => {
      "$first" => "$$ROOT.shipment_events.event_at"
    }
  }
}

Shipment.collection.aggregate([unwind, sort, group])

Please find playground example below.
https://mongoplayground.net/p/oLTG-18aIDm

huangapple
  • 本文由 发表于 2023年6月27日 19:56:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76564605.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定