如何在MongoDB中使用一个集合来映射另一个集合

时间:2020-01-17 23:44:25

标签: database mongodb mongodb-atlas

我有一个类似以下的数据集

[{id:1,month:1,count:1},{id:1,month:2,count:2},{id:1,month:3,count:3}......,
{id:2,month:1,count:1},{id:2,month:2,count:2},{id:2,month:3,count:3}.......,
........
........
{id:19,month:1,count:1},{id:19,month:2,count:2},{id:19,month:3,count:3}.......,]

,表格如下所示。

|id|month|count|
|1 |  1  | 1   | 
.............
.........
|19| 12  | 4   |

还有另一个id作为divisonId,它如下所示映射到上面的id

{1:[1,2,4,5],2:[3,6,8,9],3:[7,10,....19]}

,映射表如下所示。

|divisionId| id|
|    1     | 1 |
|    1     | 2 |
|    1     | 4 |
|    1     | 5 |
|    2     | 3 |
|    2     | 6 |
......
......

所以现在我需要汇总数据并求和并根据divisonIds重新分组。

所以最终返回的数据应该看起来像下面的

[{divsionId:1,month:1,count:19},{divisionId:1,month:2,count:53},{divisionId:1,month:3,count:66}......,
    {divisionId:2,month:1,count:21},{divisionId:2,month:2,count:82},{divisionId:2,month:3,count:63}.......,   
    {divisionId:3,month:1,count:1},{divisionId:3,month:2,count:2},{divisionId:3,month:3,count:3}.......,]

表格应该像

| divisionId| month | count |
|     1     |   1   |  200  |
|     1     |   2   |  400  |
|     1     |   3   |  300  |
.....
.....
|     3     |   11  |  500  |
|     3     |   12  |  600  |

因此,基本上,它只是将ID映射到divisionId,并汇总这些ID的各个月份,然后汇总一个新的集合以返回数据。 由于将来可能会将ID分配给不同的dividId,或者不允许仅使用聚合方法,因此我不允许将dividId放在原始表中。

当前,我可以使用的一种方法是使用Javascript根据映射分别获取ID的数据,然后进行计算并将其推入mongos以便将其存储为新集合,因此当UI查询数据时将来,它将仅读取查询,从而节省了昂贵的计算。但是如果我仅通过使用一些高级mongodb语法就能解决此问题,那就太好了。如果您有一些技巧可以使用,请告诉我。谢谢。

2 个答案:

答案 0 :(得分:0)

请尝试:

db.divisionIdCollName.aggregate([{
    $lookup:
    {
        from: "idCollectionName",
        let: { ids: "$id" },
        pipeline: [
            {
                $match:
                {
                    $expr:
                        { $in: ["$id", "$$ids"] }
                }
            }
        ],
        as: "data"
    }
}, { $unwind: { path: "$data", preserveNullAndEmptyArrays: true } },
{ $group: { _id: { divisionId: '$divisionId', month: '$data.month' }, month: { $first: '$data.month' }, count: { $sum: '$data.count' } } },
{$addFields : {divisionId : '$_id.divisionId'}}, {$project : {_id:0}}
])

结果: Mongo playground

您可以在那儿测试结果-感到聚合正在返回正确的结果后,尝试添加$merge阶段以将结果写入另一个集合,您可以使用$out代替$merge,但是我们使用$merge的原因是,如果给定名称与数据库$out中的任何集合名称匹配,则每次查询运行时它将用聚合结果替换整个集合,这将是破坏性的,如果该查询必须更新集合中的现有记录,这就是我们使用$merge的原因,请在使用前先阅读这两条记录,因此在$project之后的最后一个阶段添加以下阶段。

注意:$merge中的v 4.2$out> = v 2.6中的新内容。如果您要进行$merge,因为您要指定两个字段on: [ "divisionId", "month" ]-那么应该在集合divisionIdCollNameNew上创建一个唯一的复合索引-因此,我们需要手动创建集合并创建唯一索引,然后执行查询。

创建收藏夹和索引:

db.createCollection("divisionIdCollNameNew")     
db.divisionIdCollNameNew.createIndex ( { divisionId: 1, month: 1 }, { unique: true } )

最终阶段:

 { $merge : { into: { coll: "divisionIdCollNameNew" }, on: [ "divisionId", "month" ], whenNotMatched: "insert" } }

答案 1 :(得分:0)

假设

集合months具有以下结构:{id:1,month:1,count:1}

集合divisions具有以下结构:{1:[1,2,4,5],2:[3,6,8,9],3:[7,10,19]}

您可以执行以下查询:

db.divisons.aggregate([
  {
    $addFields: {
      data: {
        $filter: {
          input: {
            $objectToArray: "$$ROOT"
          },
          cond: {
            $isArray: "$$this.v"
          }
        }
      }
    }
  },
  {
    $unwind: "$data"
  },
  {
    $lookup: {
      from: "months",
      let: {
        ids: "$data.v"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $in: [
                "$id",
                "$$ids"
              ]
            }
          }
        }
      ],
      as: "months"
    }
  },
  {
    $unwind: "$months"
  },
  {
    $group: {
      _id: {
        divisionId: "$data.k",
        month: "$months.month"
      },
      count: {
        $sum: "$months.count"
      }
    }
  },
  {
    $project: {
      _id: 0,
      divisionId: "$_id.divisionId",
      month: "$_id.month",
      count: "$count"
    }
  },
  {
    $sort: {
      divisionId: 1,
      month: 1
    }
  }
])

MongoPlayground

EXPLANATION

您的divisions集合尚未规范化key:value对,因此我们的第一步是使用1:[...], 2:[...]运算符将[{k:"1", v:[...]}, {k:2, v:[...]}]对转换为$objectToArray对。

然后,我们将上一步中的数组$unwind展平,并将uncorrelated sub-queries$lookup应用于months集合。

最后一步,我们用$group divisionId + month乘以count的值。

为了将结果存储在另一个集合中,您需要使用$out or $merge运算符。

相关问题