mongodb 如何将$facet结果组合到所需的结构中

4sup72z8  于 2022-11-03  发布在  Go
关注(0)|答案(2)|浏览(151)

我需要从同一个集合中得到两个不同的数据集,如果任何集合中的任何数据与另一个集合中的另一个数据具有收敛性,则将它们组合成一个,如果没有,则将它们转换为所需的格式,为了使它更清楚,我认为有一个名为collection1的集合,我需要从该集合中启动具有特定条件的任务和完成具有特定条件的任务,我设法做到了这一点就像这样:

db.collection1.aggregate([{
    $facet: {
        "started":[...],
        "completed":[...]
        }
    },
  ]).toArray()

并假设started是一个如下数组:

interface Starts{
  supplier: string;
  publisher: string;
  partner: string;
  buyer: string;
  started_at: string;
  starts: number;
}

完成的是一个数组:

interface Completes{
  supplier: string;
  publisher: string;
  partner: string;
  buyer: string;
  finished_at: string;
  completes: number;
  revenue: number;
}

您会看到某些已启动的任务(具有某些supplierpartnerbuyerpublisher)可能实际上已完成,并且它们的完成信息存在于已完成的数组中,因此这两个任务需要合并,而某些任务可能未合并(而我将不会有finished_at,完成,收入信息,我会将这些值设置为null),而且一些completed tasks可能与任何started tasks都不相关(我不会为它们提供starts、started_at信息,我会为这些值设置null)因此,最终结果将类似于以下数组:

interface StartsCompletes{
  supplier: string;
  publisher: string;
  partner: string;
  buyer: string;
  started_at: string;
  finished_at: string;
  starts: number;
  completes: number;
  revenue: number;
}

我可以使用JavaScript for循环遍历facet的输出并实现它,但我是否可以在aggregate管道中添加另一个阶段并使用MongoDB来实现它?

lf3rwulv

lf3rwulv1#

我认为在内存中实现这一点可能更容易,但这里有一种使用$reduce合并数组的方法,本质上我逐项迭代数组,如果它不符合条件(供应商x合作伙伴x购买者x发布者),则将其推送到数组中,如果它确实存在,则合并两个对象。
总体上看起来像这样:

db.collection1.aggregate([
  {
    $facet: {
      "started":[...],
      "completed":[...]
    }
  },
  {
    $project: {
      merged: {
        $reduce: {
          input: {
            $concatArrays: [
              "$started",
              "$completed"
            ]
          },
          initialValue: {
            values: [],
            mapping: []
          },
          in: {
            $cond: [
              {
                $in: [
                  {
                    $concat: [
                      "$$this.supplier",
                      "$$this.partner",
                      "$$this.buyer",
                      "$$this.publisher"
                    ]
                  },
                  "$$value.mapping.key"
                ]
              },
              {
                values: {
                  $map: {
                    input: "$$value.values",
                    as: "arrValue",
                    in: {
                      $cond: [
                        {
                          $and: [
                            {
                              $eq: [
                                "$$arrValue.supplier",
                                "$$this.supplier"
                              ]
                            },
                            {
                              $eq: [
                                "$$arrValue.partner",
                                "$$this.partner"
                              ]
                            },
                            {
                              $eq: [
                                "$$arrValue.buyer",
                                "$$this.buyer"
                              ]
                            },
                            {
                              $eq: [
                                "$$arrValue.publisher",
                                "$$this.publisher"
                              ]
                            },

                          ]
                        },
                        {
                          $mergeObjects: [
                            "$$arrValue",
                            "$$this"
                          ]
                        },
                        "$$arrValue"
                      ]
                    }
                  }
                },
                mapping: "$$value.mapping"
              },
              {
                values: {
                  $concatArrays: [
                    "$$value.values",
                    [
                      "$$this"
                    ]
                  ]
                },
                mapping: {
                  $concatArrays: [
                    "$$value.mapping",
                    [
                      {
                        key: {
                          $concat: [
                            "$$this.supplier",
                            "$$this.partner",
                            "$$this.buyer",
                            "$$this.publisher"
                          ]
                        },
                        value: {
                          $size: "$$value.mapping"
                        }
                      }
                    ]
                  ]
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      mergedResults: "$merged.values"
    }
  }
])

Mongo Playground

scyqe7ek

scyqe7ek2#

另一种选择是用简单的$group代替$facet级:

db.collection.aggregate([
  {$group: {
      _id: {
        supplier: "$supplier",
        publisher: "$publisher",
        partner: "$partner",
        buyer: "$buyer"
      },
      started_at: {$max: "$started_at"},
      starts: {$max: "$starts"},
      revenue: {$max: "$revenue"},
      finished_at: {$max: "$finished_at"},
      completes: {$max: "$completes"}
  }},
  {$set: {
      buyer: "$_id.buyer",
      partner: "$_id.partner",
      publisher: "$_id.publisher",
      supplier: "$_id.supplier",
      _id: "$$REMOVE"
  }}
])

其中不应担心文档大小限制。
了解它在playground example上的工作原理

相关问题