MongoDB连接两个复杂集合

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

MongoDB join two complex collection

问题

我有两个集合

  1. data
{
  _id: ObjectId('123'),
  uuid: '123abc'
  content: 'hello'
}

{
  _id: ObjectId('456'),
  uuid: '123abc'
  content: 'hi'
}
  1. history
{
 _id: ObjectId('xxx'),
 uuid: '123abc'
 data: [{path: '/hello.json', objectId: '123'}, {path: '/hi.json', objectId: '456'}]
}

我想要

{
  _id: ObjectId('123'),
  uuid: '123abc'
  content: 'hello'
  path: '/hello.json'
}

{
  _id: ObjectId('456'),
  uuid: '123abc'
  content: 'hi'
  path: '/hi.json'
}

步骤:

  1. 使用 uuid 查找第二个 JSON
  2. 使用第二个 JSON 数据数组元素的 objectId 定位第一个 JSON

是否有人知道如何编写 MongoDB 操作以连接这两个集合?

英文:

I got two collections

  1. data
{
  _id: ObjectId('123'),
  uuid: '123abc'
  content: 'hello'
}

{
  _id: ObjectId('456'),
  uuid: '123abc'
  content: 'hi'
}

  1. history
{
 _id: ObjectId('xxx'),
 uuid: '123abc'
 data: [{path: '/hello.json', objectId: '123'}, {path: '/hi.json', objectId: '456'}]
}

I want

{
  _id: ObjectId('123'),
  uuid: '123abc'
  content: 'hello'
  path: '/hello.json'
}

{
  _id: ObjectId('456'),
  uuid: '123abc'
  content: 'hi'
  path: '/hi.json'
}

Step:

  1. use the uuid to find the second json
  2. use the objectId of the second json data array element to locate the first json

Does anyone who knows how to write the MongoDB operations to join the two collections

the result after the second stage is finished

答案1

得分: 1

你可以使用聚合框架来实现:

  • $lookup - 从 history 集合中获取数据
  • 使用 $set$first - 从 history 属性中获取第一个元素,因为 $lookup 总是返回一个数组
  • 使用 $set$filter - 创建一个 path_element 属性,其中包含基于文档 _id 进行筛选的历史记录
  • $project - 以期望的输出形式投影数据。
db.data.aggregate([
  {
    "$lookup": {
      "from": "history",
      "localField": "uuid",
      "foreignField": "uuid",
      "as": "history"
    }
  },
  {
    "$set": {
      "history": {
        "$first": "$history"
      }
    }
  },
  {
    $set: {
      path_element: {
        "$filter": {
          "input": "$history.data",
          "cond": {
            $eq: [
              {
                $toString: "$_id"
              },
              "$$this.objectId"
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      _id: 1,
      uuid: 1,
      content: 1,
      path: {
        "$getField": {
          "field": "path",
          "input": {
            $first: "$path_element"
          }
        }
      }
    }
  }
])

工作示例

英文:

You can do it with Aggregation Framework:

  • $lookup - To fetch data from the history collection
  • $set with $first - To get the first element from the history property, since the $lookup always return an array
  • $set with $filter - To create a path_element property that has the filtered history based on the document _id.
  • $project - to project the data as expected output.
db.data.aggregate([
  {
    "$lookup": {
      "from": "history",
      "localField": "uuid",
      "foreignField": "uuid",
      "as": "history"
    }
  },
  {
    "$set": {
      "history": {
        "$first": "$history"
      }
    }
  },
  {
    $set: {
      path_element: {
        "$filter": {
          "input": "$history.data",
          "cond": {
            $eq: [
              {
                $toString: "$_id"
              },
              "$$this.objectId"
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      _id: 1,
      uuid: 1,
      content: 1,
      path: {
        "$getField": {
          "field": "path",
          "input": {
            $first: "$path_element"
          }
        }
      }
    }
  }
])

Working example

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

发表评论

匿名网友

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

确定