【问题标题】:How to use MongoDB aggregation to convert a string of key value pairs into a document如何使用MongoDB聚合将一串键值对转换为文档
【发布时间】:2019-09-08 05:14:07
【问题描述】:

我正在使用 MongoDB 聚合管道尝试查看是否可以使用它来解析具有以下格式的文件。

FIELD1:ABC
FIELD2:DEF
...
FIELD12:YZ
RowData:__ __ 01 __ __
RowData:__ 02 01 01 __
RowData:__ __ 03 __ __

我已将文件流直接插入到一个名为 fileStream 的 mongo 文档中。现在我正在尝试创建一个管道来将每个字段添加到文档中。我已经取得了一些成功,但我似乎无法将具有重复值的键放入数组中。

我遇到的问题是任何重复的键都会被最后一个值覆盖。

通过这条管道,我得到一个数组数组,其中元素 0 是键,元素 1 是值。因此,当我使用 $arrayToObject 时,仅保留最后一个字段用于重复键。

db.maps.aggregate([
  {
    $addFields: {
      'rows':
      {
        $map:
        {
          input: {
            // Sinf Rows
            $filter: {
              input: { $split: ['$fileStream', '\r\n'] },
              as: 'row',
              cond: { $ne: ['$$row', ''] }
            }
          },
          as: 'row',
          in:
            {
              $split: ['$$row', ':']
            }
        }
      }
    }
  }
]).pretty()

此管道已关闭,但 RowData 元素未包含在数组中。

db.maps.aggregate([
  {
    $addFields: {
      'rows':
      {
        $map:
        {
          input: {
            // Sinf Rows
            $filter: {
              input: { $split: ['$fileStream', '\r\n'] },
              as: 'row',
              cond: { $ne: ['$$row', ''] }
            }
          },
          as: 'row',
          in:
            {
              $cond: [{ $eq: [{ $arrayElemAt: [{ $split: ['$$row', ':'] }, 0] }, 'RowData'] }, { $arrayElemAt: [{ $split: ['$$row', ':'] }, 1] }, { $split: ['$$row', ':'] }]
            }
        }
      }
    }
  }
]).pretty()

我想将所有重复的键合并到同一个数组中。

像这样的

"file": 
{
"FIELD1": "ABC"
...
"RowData": 
[
"__ __ 01 __ __",
"__ 02 01 01 __",
"__ __ 03 __ __"
]
}

我可以在 js 中使用 reduce 来做到这一点,但是如何使用聚合 $reduce 将其累积到数组或对象中?

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    以下查询可以得到我们预期的输出:

    db.maps.aggregate([
        {
            $project:{
                "file":{
                    $reduce:{
                        "input":{
                            $split:["$fileStream","\n"]
                        },
                        "initialValue":{
                            "elements":[]
                        },
                        "in":{
                            "elements":{
                                $concatArrays:[
                                    "$$value.elements",
                                    [
                                        {
                                            $let:{
                                                "vars":{
                                                    "splitted":{
                                                        $split:["$$this",":"]
                                                    }
                                                },
                                                "in":{
                                                    "k":{
                                                        $arrayElemAt:["$$splitted",0]
                                                    },
                                                    "v":{
                                                        $arrayElemAt:["$$splitted",1]
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                ]
                            }
                        }
                    }
                }
            }
        },
        {
            $unwind:"$file.elements"
        },
        {
            $group:{
                "_id":{
                    "_id":"$_id",
                    "element":"$file.elements.k"
                },
                "k":{
                    $first:"$file.elements.k"
                },
                "v":{
                    $push:"$file.elements.v"
                }
            }
        },
        {
            $addFields:{
                "v":{
                    $cond:[
                        {
                            $gt:[
                                {
                                    $size:"$v"
                                },
                                1
                            ]
                        },
                        "$v",
                        {
                            $arrayElemAt:["$v",0]
                        }
                    ]
                }
            }
        },
        {
            $group:{
                "_id":"$_id._id",
                "file":{
                    $push:{
                        "k":"$k",
                        "v":"$v"
                    }
                }
            }
        },
        {
            $project:{
                "file":{
                    $arrayToObject:"$file"
                }
            }
        }
    ]).pretty()
    

    数据集:

    {
        "_id" : ObjectId("5d73c530f04b490307453cfe"),
        "fileStream" : "FIELD1:ABC\nFIELD2:DEF\nRowData:__ __ 01 __ __\nRowData:__ 02 01 01 __\nRowData:__ __ 03 __ __"
    }
    

    输出:

    {
        "_id" : ObjectId("5d73c530f04b490307453cfe"),
        "file" : {
            "RowData" : [
                "__ __ 01 __ __",
                "__ 02 01 01 __",
                "__ __ 03 __ __"
            ],
            "FIELD2" : "DEF",
            "FIELD1" : "ABC"
        }
    }
    

    说明:

    • 将文件流转换为元素数组。每个元素都有一个键值对
    • 对键进行分组并将键的所有值推送到数组中
    • 如果大小仅为 1,则将 values 数组替换为数组的第一个值。这样做是因为如果该值是单一的,则不应将其显示为数组
    • 将所有键值对合并到一个数组中
    • 将键值对数组转换为对象

    【讨论】:

    • 哇,谢谢!我花了一些时间来完成管道,但第一个小组赛阶段真的很重要。我在 reduce 输入中添加了一个过滤器,以消除文件中的任何空白行` $filter: { input: { $split: ['$fileStream', '\r\n'] }, as: 'row', cond: { $ne: ['$$row', ''] } }`
    猜你喜欢
    • 2019-08-09
    • 2019-03-15
    • 2023-03-17
    • 1970-01-01
    • 2022-01-22
    • 2016-11-03
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    相关资源
    最近更新 更多