Есть ли простой способ получить значение ключа на втором уровне в карте объектов?

-8

Я пишу несколько Node.js для развертывания AWS CloudFormation Stacks на основе шаблонов YAML, хочу сделать один сценарий универсальным для всех шаблонов и поэтому хочу проанализировать YAML для обнаружения определенных функций, так как это повлияет на вызов API. У меня есть способ конвертировать YAML обратно в JSON, а затем...

Для целей этого примера я хочу узнать, есть ли какие-либо ресурсы IAM (типа "AWS :: IAM :: Role", "AWS :: IAM :: Group"), и есть ли какие-либо из этих ресурсов с явными именами. Я должен указать возможность CAPABILITY_IAM для неназванного ресурса IAM, но нужно использовать CAPABILITY_NAMED_IAM, если у него есть имя.

Я сделал это с .map() и .filter(), когда это массив объектов, но этот формат является картой объектов, так что это не будет работать. Кажется, я не могу найти простой "однострочный" способ сделать что-то похожее - возможно, я не знаю правильных условий поиска?

Итак, для этого (отредактировано, чтобы уменьшить) вход:

{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"UnnamedRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"Path": "/"
}
},
"NamedRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "SomeName"
"Path": "/"
}
},
"IrrelevantNonIAMResource": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "SomeFunction"
}
}
}
}

Итак, первая проблема - в надежде получить такой вывод:

  "Resources": {
"UnnamedRole": {
"Type": "AWS::IAM::Role",
"Needs": "CAPABILITY_IAM"
},
"NamedRole": {
"Type": "AWS::IAM::Role",
"Needs": "CAPABILITY_NAMED_IAM"
}
}

Дополнительный кредит!! - ответ всего одним словом:

    NONE = Ресурсы IAM не найдены, для которых нужна возможность CAPABILITY_IAM = По крайней мере один IAM найден без имени CAPABILITY_NAMED_IAM = По крайней мере один IAM найден с именем -

@Джеймс попросил код - у меня нет ничего по этому поводу, почему я здесь. Но я хотел получить что-то, что выглядело ближе к этому стилю - что-то, что я использую, чтобы найти связанные домены в Route53, где HostedZones - массив объектов. Ресурсами выше является карта объектов:

let zones = data.HostedZones.filter(z => z.Config.PrivateZone == false)
.map(z => ({ Id: z.Id.replace('/hostedzone/',''), Name: z.Name}))
.filter(z => z.Name.includes(domainName));

Существует ли подобный короткий синтаксис для выполнения того, что я хочу, в одной длинной строке?

Любая хорошая ссылка на то, где эта тема освещена. Новичок в Node - не смог ничего найти за 2 часа поиска.

спросил(а) 2021-01-25T18:37:14+03:00 5 месяцев назад
1
Решение
88

Это может быть сделано с помощью reduce функции (кстати, у Вас есть ошибка в этой строке "RoleName": "SomeName", она должна закончиться ,).

Object.keys(o.Resources).reduce((acc, v) => {
if (o.Resources[v].Type === "AWS::IAM::Role" && o.Resources[v].Properties.RoleName) {
acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_NAMED_IAM"}
} else if (o.Resources[v].Type === "AWS::IAM::Role") {
acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_IAM" }
}
return acc;
}, { Resources: {}});

const o = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"UnnamedRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"Path": "/"
}
},
"NamedRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "SomeName",
"Path": "/"
}
},
"IrrelevantNonIAMResource": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "SomeFunction"
}
}
}
}

const res = Object.keys(o.Resources).reduce((acc, v) => {
if (o.Resources[v].Type === "AWS::IAM::Role" && o.Resources[v].Properties.RoleName) {
acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_NAMED_IAM"}
} else if (o.Resources[v].Type === "AWS::IAM::Role") {
acc.Resources[v] = { Type: "AWS::IAM::Role", Needs: "CAPABILITY_IAM" }
}
return acc;
}, { Resources: {}});

console.log(res);

ответил(а) 2021-01-25T18:37:14+03:00 5 месяцев назад
45

Похоже, что не существует собственного способа выполнения того, что вы просите, поэтому забудьте об этом, как об однострочных выражениях, но (как указано в связанном ответе) вы можете написать свою собственную функцию objectMap.

С другой стороны, вы можете использовать некоторые служебные библиотеки, такие как lodash, которые позволят вам делать что-то наподобие того, что вы просите, используя их функции .chain и .map, которые могут перебирать объекты.

Надеюсь, это поможет вам!

ответил(а) 2021-01-25T18:37:14+03:00 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема