mongoexport - Leaf Level - преобразование JSON в CSV - egrep не работает с несколькими шаблонами, используя "|" труба или с опцией -f
Зачем egrep
не дает мне все соответствующие записи?
Это мой простой JSON-объект:
[nukaNUKA@dev-machine csv]$ cat jsonfile.json
{"number": 303,"projectName": "giga","queueId":8881,"result":"SUCCESS"}
Это мой файл шаблона (чтобы я не напугал редактора):
[nukaNUKA@dev-machine csv]$ cat egrep-pattern.txt
\"number\":.*\"projectName
\"projectName\":.*,\"queueId
\"queueId\":.*,\"result
\"result\":\".*$
Это команда egrep/grep для индивидуального поиска, которая работает!:
[nukaNUKA@dev-machine csv]$ egrep -o "\"number\":.*\"projectName" jsonfile.json
"number": 303,"projectName
[nukaNUKA@dev-machine csv]$ egrep -o "\"projectName\":.*,\"queueId" jsonfile.json
"projectName": "giga","queueId
[nukaNUKA@dev-machine csv]$ egrep -o "\"queueId\":.*,\"result" jsonfile.json
"queueId":8881,"result
[nukaNUKA@dev-machine csv]$ egrep -o "\"result\":\".*$" jsonfile.json
"result":"SUCCESS"}
Итак, это не сработало? Я не ношу очки, да.
[nukaNUKA@dev-machine csv]$ egrep -o "\"number\":.*\"projectName|\"projectName\":.*,\"queueId|\"queueId\":.*,\"result|\"result\":\".*$" jsonfile.json
"number": 303,"projectName
"queueId":8881,"result
[nukaNUKA@dev-machine csv]$ egrep -o -f egrep-pattern.txt jsonfile.json
"number": 303,"projectName
"queueId":8881,"result
[nukaNUKA@dev-machine csv]$
У меня есть сложный вложенный большой двоичный объект JSON, и, поскольку все неструктурировано, кажется, что я не могу использовать JQ или JSONV или что-либо другое сценарий Python (поскольку данные, которые я ищу, хранятся в массивах, содержащих 1 словарные записи (ключ = значение) с теми же именами ключей для того, что я ищу (например: { "parameters": [ { "name": "jobname", "value": "shenzi" }, { "name": "pipelineVersion", "value": "1.2.3.4" }, ...so on..., ... ]
) и индекс для имени задания и pipeVersion или аналогичных имён параметров не находится в одном и том же месте индекса [X] в каждой записи JSON, которую я имею.
В худшем случае, я могу добавить условные проверки, чтобы увидеть, совпадает ли ключ в каждом индексе, имя задания и т. Д., А затем я получаю те поля, которые я ищу, но есть сотни таких полей, которые я хочу получить. Я не хочу жестко их кодировать, если это возможно.
Я думал, что моя запись JSON для каждой строки, я могу просто написать классные шаблоны (безобразно, я знаю), но по крайней мере тогда мне не нужно беспокоиться об условном коде или просто использовать мощность BASH/sed/tr/cut для получения что мне нужно но похоже egrep -f or -o ...
не работает, как показано выше.
Пример объекта BLOB-объекта JSON (из одного задания Дженкинса). В одной коллекции JenkinsJobsBuild в MongoDB есть разные записи JSON для создания BLOB-объектов JSON (каждая имеет разные структуры JSON, параметры и т. Д.). См. Прикрепленный образец объекта JSON.
{
"_id": {
"$oid": "5120349es967yhsdfs907c4f"
},
"actions": [
{
"causes": [
{
"shortDescription": "Started by an SCM change"
}
]
},
{
},
{
"oneClickDeployPossible": false,
"oneClickDeployReady": false,
"oneClickDeployValid": false
},
{
},
{
},
{
},
{
"cspec": "element * ...\/MyProject_latest_int\/LATESTnelement * ...\/MyProject_integration\/LATESTnelement \/vobs\/some_vob\/gigi \/main\/myproject_integration\/MyProject_Slot_0_maint_int\/LATESTnelement * ...\/myproject_integration\/LATESTnelement \/vobs\/some_vob \/main\/LATEST",
"latestBlsOnConfiguredStream": null,
"stream": null
},
{
},
{
"parameters": [
{
"name": "CLEARCASE_VIEWTAG",
"value": "jenkins_MyProject_latest"
},
{
"name": "BUILD_DEBUG",
"value": false
},
{
"name": "CLEAN_BUILD",
"value": true
},
{
"name": "BASEVERSION",
"value": "7.4.1"
},
{
"name": "ARTIFACTID",
"value": "lowercaseprojectname"
},
{
"name": "SYSTEM",
"value": "myprojectSystem"
},
{
"name": "LOT",
"value": "02"
},
{
"name": "PIPENUMBER",
"value": "7.4.1.303"
}
]
},
{
},
{
},
{
"parameters": [
{
"name": "DESCRIPTION_SETTER_DESCRIPTION",
"value": "lowercaseprojectname_V7.4.1.303"
}
]
},
{
},
{
},
{
},
{
}
],
"artifacts": [
],
"building": false,
"builtOn": "servername",
"changeSet": {
"items": [
{
"affectedPaths": [
"vobs\/some_vob\/myproject\/apps\/app1\/Java\/test\/src\/com\/giga\/highlevelproject\/myproject\/schedule\/validation\/SomeActivityTest.java"
],
"author": {
"absoluteUrl": "http:\/\/11.22.33.44:8080\/user\/hitj1620",
"fullName": "name1, name2 A"
},
"commitId": null,
"date": {
"$numberLong": "1489439532000"
},
"dateStr": "13\/03\/2017 21:12:12",
"elements": [
{
"action": "create version",
"editType": "edit",
"file": "vobs\/some_vob\/myproject\/apps\/app1\/Java\/test\/src\/com\/giga\/highlevelproject\/myproject\/schedule\/validation\/SomeActivityTest.java",
"operation": "checkin",
"version": "\/main\/MyProject_latest_int\/2"
}
],
"msg": "",
"timestamp": -1,
"user": "user111"
}
],
"kind": null
},
"culprits": [
{
"absoluteUrl": "http:\/\/11.22.33.44:8080\/user\/nuka1620",
"fullName": "nuka, Chuck"
}
],
"description": "lowercaseprojectname_V7.4.1.303",
"displayName": "#303",
"duration": 525758,
"estimatedDuration": 306374,
"executor": null,
"fullDisplayName": "MyProject \u00bb MyProject-build #303",
"highlevelproject_metrics_source_url": "http:\/\/11.22.33.44:8080\/job\/MyProject\/job\/MyProject-build\/303\/\/api\/json",
"id": "303",
"keepLog": false,
"number": 303,
"projectName": "MyProject-build",
"queueId": 8201,
"result": "SUCCESS",
"timeToRepair": null,
"timestamp": {
"$numberLong": "1489439650307"
},
"url": "http:\/\/11.22.33.44:8080\/job\/MyProject\/job\/MyProject-build\/303\/"
}
2 ответа
Когда регулярные выражения находятся в файле, вам не нужно экранировать двойные кавычки; вам не нужно сражаться, чтобы получить двойные кавычки за раковиной.
"number":.*"projectName
"projectName":.*,"queueId
"queueId":.*,"result
"result":".*$
Когда это исправлено, я получаю:
$ egrep -o -f egrep-pattern.txt jsonfile.json
"number": 303,"projectName
"queueId":8881,"result
$
Проблема сейчас в том, я думаю, что вы потребляли projectName
с первым шаблоном, так что у других не будет шанса сравниться с ним. Измените шаблоны для чтения до запятой, и вы можете получить лучшие результаты:
"number":[^,]*
"projectName":[^,]*
"queueId":[^,]*
"result":".*$
выходы:
"number": 303
"projectName": "giga"
"queueId":8881
"result":"SUCESS"}
Вы можете попытаться быть более деликатным, но вы быстро достигнете точки, когда инструмент с поддержкой JSON станет более разумным. Например, запятые в строковом значении могут испортить измененные регулярные выражения. (Итак, если бы проект назывался "Гига, если не Тера", у вас были бы проблемы.)
Соответствие более общему имени JSON: нотация значения
Пока вы ищете простой "key":"quoted value"
объекты, вы можете использовать следующие grep -E
(ака egrep
) команда:
grep -Eoe '"[^"]+":"((\\(["\\/bfnrt]|u[0-9a-fA-F]{4}))|[^"])*"' data
Учитывая JSON-подобные данные (в файле под названием data
):
{"key1":"value","key2":"value2 with \"quoted\" text","key3":"value3 with \\ and \/ and \f and \uA32D embedded"}
этот скрипт производит:
"key1":"value"
"key2":"value2 with \"quoted\" text"
"key3":"value3 with \\ and \/ and \f and \uA32D embedded"
Вы можете обновить его для обработки практически любого действующего JSON "key":value
используя:
grep -Eoe '"[^"]+":(("((\\(["\\/bfnrt]|u[0-9a-fA-F]{4}))|[^"])*")|true|false|null|(-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?))' data
С новым data
файл, содержащий:
{"key1":"value","key2":"value2 with \"quoted\" text"}
{"key3":"value3 with \\ and \/ and \f and \uA32D embedded"}
{"key4":false,"key5":true,"key6":null,"key7":7,"key8":0,"key9":0.123E-23}
{"key10":10,"key11":3.14159,"key12":0.876,"key13":-543.123}
скрипт выдает:
"key1":"value"
"key2":"value2 with \"quoted\" text"
"key3":"value3 with \\ and \/ and \f and \uA32D embedded"
"key4":false
"key5":true
"key6":null
"key7":7
"key8":0
"key9":0.123E-23
"key10":10
"key11":3.14159
"key12":0.876
"key13":-543.123
Вы можете следовать железнодорожным схемам в спецификации JSON схемы на http://json.org/ чтобы увидеть, как я создал регулярное выражение.
Это может быть усилено разумным добавлением [[:space:]]*
в местах, где пробелы разрешены, но не обязательны - до ключевой строки, до двоеточия, после двоеточия (вы могли бы добавить его и после значения, но, вероятно, вам это не нужно).
Другое упрощение, которое я принял, заключается в том, что ключ не учитывает различные escape-символы, которые делает строка значения. Вы могли бы повторить это.
И, конечно же, это работает только для "листьев" name: value пары; если значение само является объектом {…}
или массив […]
это не обрабатывает значение в целом.
Тем не менее, это просто подчеркивает, что это очень быстро запутывается, и вам лучше использовать специальный инструмент запросов JSON. Одним из таких инструментов является jq
, как упоминалось в комментарии к основному запросу.
У меня был сложный BLOB-объект JSON от Дженкинса (то есть данные RestAPI работы Дженкинса), который был у меня в базе данных MongoDB.
Чтобы получить его из MongoDB, я использовал команду mongoexport для генерации (не JsonArray или не Pretty) блоба JSON успешно.
#/bin/bash
server=localhost
collectionFile=collections.txt
## Generate collection file contains all collections in the Jenkins database in MongoDB.
( set -x
mongo "mongoDbServer.company.com/database_Jenkins" --eval "rs.slaveOk();db.getCollectionNames()" --quiet > ${collectionFile}
)
## create collection based JSON files
for collection in $(cat ${collectionFile} | sed -e 's:,: :g')
do
mongoexport --host ${server} --db ${db} --collection "${collection}" --out ${exportDir}/${collection}.json
##mongoexport --host ${server} --db ${db} --collection "${collection}" --type=csv --fieldFile ~/mongoDB_fetch/get_these_csv_fields.txt --out ${exportDir}/${collection}.csv; ## This didn't work if you have nested fields. fieldFile file was just containing field name per line in a particular xyz.IndexNumber.yyy format.
done
Пробовал встроенную команду монгоэкспорта --type=csv
с -f
поля для ловли topfield.0.subField, field2, field3.7.parameters.7..
ничего не получалось.
PS: number
после .
mark - это способ определения индексов, если вы собираетесь создать файл CSV и использовать поля (обязательные), используя mongoexport
команда.
Поскольку вся моя структура JSON была неструктурированной (выпады / обновления версии Jenkins происходили в прошлом, а данные о задании не совпадали), я попробовал это окончательно sed
трюк (так как данные JSON на запись были в каждой отдельной строке).
это sed
Команда (как показано ниже) выдаст вам все ключи и их значения (в формате ключ = значение) на строку в поле LEAF ключ = уровень значения практически любого BLSON-объекта / по крайней мере из BLOB- объекта Jenkins JSON. Получив эту информацию, вы можете передать выходные данные этой команды во временный файл, а затем прочитать всю часть значения (после =
Отметьте) и создайте файл CSV в соотв. ДА, вы должны отсортировать его так, чтобы поля вашего CSV-файла сохранялись в порядке имен заголовков и, таким образом, значения вставлялись в правый столбец / поле. Я вычислил имена полей из временного ключа всего разного набора JSON-файла = значения сгенерированного ключа. Затем прочитайте все временные файлы коллекции и добавьте значения в соотв. в окончательный файл CSV под соответствующим заголовком / полем / столбцом.
ОК, это странное решение, но, по крайней мере, это решение - в одном лайнере.
cat myJenkinsJob.json | sed "s/{}//g;s/,,*/,/g;s/},\"/\n/g;s/},{/\n/g;s/\([^\"a-zA-Z]\),\"/\1\n/g;s/:\[{/\n/g;s/\"name\":\"//g;s/\",\"value//g;s/,\"/\n/g;s/\":\"*/=/g;s/\"//g;s/[\[}\]]//g;s/[{}]//g;s/\$[a-zA-Z][a-zA-Z]*=//g"|grep "=" | sed "s/,$//"|egrep -v "=-|=$|=\[|^_class="
Настроить это в соотв. к вашему собственному решению для sed
немного, если ваш шарик JSON показывает забавные символы, которые вам не нужны. Порядок операций sed ниже важен. Я также исключаю любые избыточные переменные (которые мне сейчас не нужны, например, BLOB-объект ex: JSON содержал значения _class="..."), поэтому я исключаю их через egrep -v
после последнего |
труба.