在Node.js应用程序中,我们有从MongoDB迁移到PostgreSQL的要求.我们的Express API大量使用MongoDB aggregation框架,我们必须用PostgreSQL重写它.例如,我们有以下形式的数据:

[{
    "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编写一个查询,它的作用就像上面的查询一样,一个阶段的输出被输入到另一个阶段.我有一些使用SQL的经验,但从未使用过PostgreSQL.但我知道PostgreSQL支持JSON数据.我的猜测是,在SQL中,我会做如下操作:

SELECT * from (SELECT * from table_name group by field_name1) group by field_name2;

基本上,我正在try 判断PostgreSQL中是否存在这样的管道功能,但找不到.

在这方面我需要一些指导. 提前谢谢!

推荐答案

WITH app_projects AS (
  SELECT 
    application,
    product,
    jsonb_agg(
      jsonb_build_object(
        'project', project, 
        'version', version
      )
    ) AS projects
  FROM 
    CompanyTable
  GROUP BY 
    application, 
    product
),
prod_apps AS (
  SELECT 
    product,
    jsonb_agg(
      jsonb_build_object(
        'application', application, 
        'projects', projects
      )
    ) AS applications
  FROM 
    app_projects
  GROUP BY 
    product
)
SELECT 
  product AS _id,
  applications
FROM 
  prod_apps;

我在PostgreSQL中使用了这里的CTE.你可以在这里阅读更多,很好的解释: https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-cte/

  1. app_projectsCTE中,对于每个applicationproduct,我使用jsonb_aggjsonb_build_object函数将项目和版本分组到一个json对象数组中.

  2. prod_appsCTE中,我将前一次CTE的结果按product分组,并为包含applications及其projects的每个产品创建一个json对象array.

最后,我从prod_appsCTE中 Select 所有结果以获得所需的输出.

jsonb_build_object--这是一个函数

jsonb_build_object(
    'project', project, 
    'version', version
)

工作原理如下:

{'project': project, 'version': version}

jsonb_agg--这是一种表达 如果你有some_value个:

some_value
------
1
2
3

jsonb_agg(some_value)个将会是:

jsonb_agg
---------
[1, 2, 3]

Mongodb相关问答推荐

如何在Mongo中制作全覆盖索引

使用MongoDB 4将根文档替换为数组

Mongoose 聚合和多级组

如何使用指南针连接到 mongodb replicaset (k8s)

如何在 go mongo-driver 中为 options.FindOne() 设置限制

Mongoose - $project 嵌套的对象数组到数组的根级别

MongoDB 聚合使用 $match 和 $expr 和数组

MongoDB:使用数组过滤器进行更新插入

Meteor 和 Fibers/bindEnvironment() 是怎么回事?

MongoDB中的readPreference和readConcern有什么区别?

在mongo聚合中将ObjectID转换为字符串

具有多个字段的mongodb文本搜索

在 Nodejs 中配置最大旧空间大小

不能在模块外使用 import 语句

有没有办法自动更新 MongoDB 中的两个集合?

Ruby 按键值分组哈希

使用 Node.js 将许多记录插入 Mongodb 的正确方法

MongoDB 中的多个 $inc 更新

Mongoose - 获取 _id 列表而不是具有 _id 的对象数组

如何判断 MongoDB 中是否存在字段?