将数组封装/转换为对象数组

时间:2017-01-15 07:20:28

标签: mongodb mongodb-query aggregation-framework

我目前正在修改架构,我需要使用聚合框架和bulkWrite进行相对简单的转换。

我希望能够接受这个数组:

{ 
     ...,
     "images" : [
        "http://example.com/...", 
        "http://example.com/...", 
        "http://example.com/..."
    ] 
}

并聚合到一个类似的数组,其中原始值被封装

{ 
     ...,
     "images" : [
        {url: "http://example.com/..."}, 
        {url: "http://example.com/..."}, 
        {url: "http://example.com/..."}
    ] 
}

查询有效,但展开整个集合的成本非常昂贵。

[
    {
        $match: {}
    },
    {
        $unwind: {
            path : "$images",
        }
    },
    {
        $group: {
            _id: "$_id",
            images_2: {$addToSet: {url: "$images"}}
        }
    },
]

如何通过project或其他更便宜的汇总来实现这一目标?

2 个答案:

答案 0 :(得分:3)

$map表达式可以完成这项工作,试试这个:

db.col.aggregate([
  {
    $project: {
      images: {
        $map: {
          input: '$images',
          as: 'url',
          in: {
            url: '$$url'
          }
        }
      }
    }
  }
]);

答案 1 :(得分:1)

您无需使用bulkWrite()方法。

您可以使用$map聚合数组运算符将表达式应用于数组中的每个元素元素。

这里,表达式只是创建一个新对象,其中值是数组中的项。

let mapExpr = {
    "$map": {
        "input": "$images",
        "as": "imageUrl",
        "in": { "url": "$$imageUrl }
    }
};

最后,您可以使用$out聚合管道运算符覆盖您的集合或将结果写入不同的集合。

当然$map不是聚合管道运算符,这意味着必须在管道阶段使用$map表达式。

执行此操作的方式取决于您的MongoDB版本。

最好的方法是在MongoDB 3.4中使用$addFields来更改文档中“images”字段的值。

db.collection.aggregate([
    { "$addFields": { "images": mapExpr }},
    { "$out": "collection }
])

从MongoDB 3.2向后,您需要使用$project管道阶段,但还需要在文档中手动包含所有其他字段

db.collection.aggregate([
    { "$project": { "images": mapExpr } },
    { "$out": "collection }
])