对象中的 ConvertTo-Json 数组为 属性 值

ConvertTo-Json in object with array as property value

在 Windows Powershell 中,我有一个简单的 Invoke-SqlCmd 查询,其中 returns 以下 table:

ID Text
-- ----
 1 FOO 
 2 BAR 
 3 SPAM

将其通过管道传输到 | ConvertTo-Json -Depth 1 会产生以下结果:

[
    {
        "RowError":  "",
        "RowState":  1,
        "Table":  "",
        "ItemArray":  "1 FOO",
        "HasErrors":  false,
        "ID":  1,
        "Text":  "FOO"
    },
    {
        "RowError":  "",
        "RowState":  1,
        "Table":  "",
        "ItemArray":  "2 BAR",
        "HasErrors":  false,
        "ID":  2,
        "Text":  "BAR"
    },
    {
        "RowError":  "",
        "RowState":  1,
        "Table":  "",
        "ItemArray":  "3 SPAM",
        "HasErrors":  false,
        "ID":  3,
        "Text":  "SPAM"
    }
]

我想要的输出不是这个裸数组,而是一个 object 有一个 属性 有 "Products" 作为名称,数组作为值。

此外,我希望我的数组条目是仅具有 SQL table 列作为属性的对象。

也就是说,我想要的输出是:

{
    "Products": [
        {
            "ID": 1,
            "Text": "FOO"
        },
        {
            "ID": 2,
            "Text": "BAR"
        },
        {
            "ID": 3,
            "Text": "SPAM"
        }
    ]
}

如何实现?


编辑:来自SQL Server Management Studio 的查询及其结果如下:

假设 $queryResult 包含您的 Invoke-SqlCmd 调用的结果:

[pscustomobject] @{ 
  Products = @($queryResult | Select-Object ID, Text)
} | ConvertTo-Json
  • Select-Object 创建 [pscustomobject] 个实例,其中仅包含表示实际 table 列的属性,在这种情况下是硬编码的。

    • 注意:动态地确定这些列名称是一种更通用的解决方案 - 请参阅下一节。
  • @()array-subexpression operator 确保结果被视为数组(以防您的查询恰好 return 只是 行)。

  • [pscustomobject] @{ ... } 是用于创建包装器 [pscustomobject] 实例的语法糖,其唯一的 属性、Products 包含列值数组-只有对象。

  • ConvertTo-Json 将生成的自定义对象转换回 JSON.

    • 虽然这里不是问题,但请注意递归深度默认限制为 2,需要显式使用 -Depth 以防止数据丢失 - 请参阅 .

动态确定列名:

Mathias R. Jessen, assisted by Fry Simpson,解决了这个问题。

通过 Invoke-SqlCmd 调用 return 一个 System.Data.Table 实例
通过 -OutputAs DataTables.Column.ColumnNames 可用于将查询的列名提取为数组:

# Note the use of `-OutputAs DataTables`; `-As DataTables` should work too.
$queryResult = Invoke-SqlCmd -OutputAs DataTables -Query "SELECT * FROM Schema1.dbo.Table_1" -ServerInstance $instanceName -Database $databaseName  

[pscustomobject] @{ 
  Products = @($queryResult | Select-Object $queryResult.Columns.ColumnName) 
} | ConvertTo-Json 

默认情况下,Invovke-SqlCmd return 是单个 System.Data.DataRow 个实例的流。

请注意,即使 $queryResult 包含一个 System.Data.DataTable 实例,它的 也会通过管道隐式发送;换句话说:$queryResult | ...$queryResult.Rows | ... 相同,后者是 PowerShell 中内置的行为。