You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从MongoDB迁移至PostgreSQL:编写PostgreSQL aggregation管道查询

将MongoDB聚合查询迁移为PostgreSQL查询

我们的Node.js Express应用需要从MongoDB迁移到PostgreSQL,现有API大量使用MongoDB的聚合框架,需要把这些聚合查询改写为PostgreSQL查询。已知规则:一个应用仅属于一个产品,一个项目仅属于一个应用,必须严格输出指定的嵌套JSON结构。

示例数据

[
  {
    "product": "PD1",
    "application": "A",
    "project": "PR1",
    "version": "1"
  },
  {
    "product": "PD1",
    "application": "A",
    "project": "PR2",
    "version": "3"
  },
  {
    "product": "PD1",
    "application": "B",
    "project": "PR3",
    "version": "2"
  },
  {
    "product": "PD2",
    "application": "C",
    "project": "PR4",
    "version": "5"
  },
  {
    "product": "PD2",
    "application": "C",
    "project": "PR5",
    "version": "2"
  }
]

原MongoDB聚合查询

let data = await CompanyModel.aggregate([
  {
    $group: {
      "_id": "$application",
      "projects": {
        $push: {
          "project": "$project",
          "version": "$version"
        }
      },
      "product": {$first: "$product"}
    }
  },
  {
    $group: {
      "_id": "$product",
      "applications": {
        $push: {
          "application": "$_id",
          "projects": "$projects"
        }
      },
    }
}])

目标输出结构

[
  {
    "_id": "PD2",
    "applications": [
      {
        "application": "C",
        "projects": [
          {"project": "PR4", "version": "5"},
          {"project": "PR5", "version": "2"}
        ]
      }
    ]
  },
  {
    "_id": "PD1",
    "applications": [
      {
        "application": "B",
        "projects": [{"project": "PR3", "version": "2"}]
      },
      {
        "application": "A",
        "projects": [
          {"project": "PR1", "version": "1"},
          {"project": "PR2", "version": "3"}
        ]
      }
    ]
  }
]

核心问题与解决方案

PostgreSQL完全支持类似MongoDB的管道式分组逻辑,你可以用嵌套子查询或者**CTE(公共表表达式)**来实现多阶段聚合,两者本质都是将前一阶段的输出作为后一阶段的输入。以下是两种实现方式:

方式1:嵌套子查询

直接用嵌套结构,结合PostgreSQL的jsonb_build_object和jsonb_agg函数构造嵌套JSON:

SELECT
  product AS "_id",
  jsonb_agg(
    jsonb_build_object(
      'application', application,
      'projects', projects
    )
  ) AS "applications"
FROM (
  SELECT
    application,
    product,
    jsonb_agg(
      jsonb_build_object(
        'project', project,
        'version', version
      )
    ) AS projects
  FROM company_table -- 替换为你的实际表名
  GROUP BY application, product
) AS app_group
GROUP BY product;

方式2:CTE(管道式写法)

CTE把每个聚合阶段拆分成独立的命名步骤,和MongoDB的聚合管道逻辑更对应,可读性更强:

WITH app_group AS (
  SELECT
    application,
    product,
    jsonb_agg(
      jsonb_build_object(
        'project', project,
        'version', version
      )
    ) AS projects
  FROM company_table -- 替换为你的实际表名
  GROUP BY application, product
)
SELECT
  product AS "_id",
  jsonb_agg(
    jsonb_build_object(
      'application', application,
      'projects', projects
    )
  ) AS "applications"
FROM app_group
GROUP BY product;

关键函数说明

  • jsonb_build_object(key1, val1, key2, val2):构造单个JSON对象,对应MongoDB里的字段映射。
  • jsonb_agg(json_obj):将多个JSON对象聚合为数组,对应MongoDB的$push操作。
  • 由于已知一个应用仅属于一个产品,第一阶段按application和product分组是安全的,也可以用MAX(product)或MIN(product)替代直接分组,结果一致。

输出纯JSON数组

如果需要输出无列名的纯JSON数组,可再用json_agg聚合最终结果:

SELECT json_agg(result)
FROM (
  SELECT
    product AS "_id",
    jsonb_agg(
      jsonb_build_object(
        'application', application,
        'projects', projects
      )
    ) AS "applications"
  FROM (
    SELECT
      application,
      product,
      jsonb_agg(
        jsonb_build_object(
          'project', project,
          'version', version
        )
      ) AS projects
    FROM company_table
    GROUP BY application, product
  ) AS app_group
  GROUP BY product
) AS result;

内容的提问来源于stack exchange,提问作者Kanojian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 20:23:14