MongoDB: конвертировать массив в CSV для сложных данных - PullRequest
0 голосов
/ 23 октября 2018

У нас есть документы MongoDB, называемые Notes, которые состоят из секции Layout и секции Data.Раздел Data использует раздел Layout для описания и маркировки полей.Например, вот упрощенный образец документа Note:

{
  "_id" : ObjectId("5aafefbecbf20b364c14d037"),
  "Title" : "Some Note Name",
    "CreatedDate" : ISODate("2018-10-22T13:12:20.343-04:00"),
  "Layout" : {
    "Name" : "Some Layout Name",
    "ComponentId" : "531a5112-2467-410c-a477-936c6527256b",
    "Tabs" : [
      {
        "Name" : "Some Tab Name",
        "Icon" : "tab",
        "Sections" : [
          {
            "Name" : "Some Section Name",
            "MappingId" : "SomeSectionId",
            "Sets" : [
              {
                "SetId" : NumberLong("1"),
                "Questions" : [
                  {
                    "MappingId" : "SomeShortAnswerId",
                    "Label" : "Some Short Answer Label",
                    "Set" : NumberLong("1"),
                    "QuestionType" : "ShortAnswer"
                  },
                  {
                    "MappingId" : "SomeMultipleChoiceId",
                    "Label" : "Some Multiple Choice Label",
                    "Set" : NumberLong("1"),
                    "QuestionType" : "MultipleChoice"
                  },
                  {
                    "MappingId" : "SomeYesNoId",
                    "Label" : "Some Yes No Label",
                    "Set" : NumberLong("1"),
                    "QuestionType" : "YesNo"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  "Data" : {
    "SomeSectionId" : [
      {
        "SomeShortAnswerId" : "blah blah blah",
        "SomeMultipleChoiceId" : [
          "Answer 1",
          "Answer 2",
          "Answer 3"
        ],
        "SomeYesNoId" : true
      }
    ]
  }
}

Вы можете видеть, что имена полей раздела Data соответствуют Layout.Tabs.Sections MappingId и Questions.MappingId.Мой текущий запрос работает для возврата только части данных:

db.myCollection.aggregate( 
  [
    { $project: { CreatedDate: 1, Data: 1 } },
    { $unwind: "$Data.SomeSectionId" },
    {
        $addFields: {
            "Data.SomeSectionId.CreatedDate": "$CreatedDate",
            "Data.SomeSectionId._id": "$_id"
        }
    },
    { $replaceRoot: { newRoot: "$Data.SomeSectionId" } }
  ]
)

и возвращенных данных:

{
  "SomeShortAnswerId" : "blah blah blah",
  "SomeMultipleChoiceId" : [
    "Answer 1, Answer 2, Answer 3"
  ]
  "SomeYesNoId" : true
}

К сожалению, эти данные передаются приложению для составления отчетов, которое имеет ограничения и не можетобрабатывать значения подмассива для ответов на вопросы с множественным выбором.

Вместо этого мне нужно отформатировать данные следующим образом:

{
  "SomeShortAnswerId" : "blah blah blah",
  "SomeMultipleChoiceId" : "Answer 1, Answer 2, Answer 3",
  "SomeYesNoId" : true
}

Что делает весь этот процесс настолько сложным, что кроме имени поля Data все остальные имена полей находятся вLayout section (MappingId s).

Может кто-нибудь предложить способ преобразования массивов ответов в одно текстовое значение через запятую, учитывая самоописывающую природу наших Note документов?Это убивает меня ...

Обновление

Возможно, я не дал понять, что содержимое примечания выше не имеет фиксированных полей.Я не могу рассчитывать на то, что SomeShortAnswerId, SomeMultipleChoiceId или SomeYesNoId будут там.Эти поля могут быть или могут быть дополнительные поля с множественным выбором для преобразования в формат CSV.Все это основано на содержимом раздела Layout.

Можно ли выполнить итерацию по всем полям раздела (Data) без указания фактического имени поля?Если бы это было возможно, я мог бы применить $ limit к каждому полю.

1 Ответ

0 голосов
/ 29 октября 2018

Основываясь на предложениях Алекса Блекса, я смог разработать решение с использованием функций агрегирования $objectToArray, $reduce, $group и $arrayToObject с либеральным использованием $project, $replaceRoot, $group, $addToSet и несколько других распространенных.На самом деле ключом было использование $objectToArray и $arrayToObject, поскольку оно не требовало знания имен свойств.

Вот мой слегка измененный запрос:

db.myCollection.aggregate([
    {
        $match: {
            "_id": { $eq: ObjectId("5aafefbecbf20b364c14d037") }
        }
    },
    {
        $project: {
            CreatedDate: 1,
            data: { $objectToArray: "$$ROOT.Data" }
        }
    },
    {
        $addFields: {
            "data.v.CreatedDate": "$CreatedDate",
            "data.v._id": "$_id"
        }
    },
    { $unwind: "$data" },
    { $unwind: "$data.v" },
    { $replaceRoot: { newRoot: "$data.v" } },
    { $project: { data: { $objectToArray: "$$ROOT" } } },
    { $unwind: "$data" },
    {
        $project: {
            "Question": "$data.k",
            "Answer": {
                $switch: {
                    branches: [
                        {
                            case: { $eq: [{ $type: "$data.v" }, "array"] },
                            then: {
                                $reduce: {
                                    input: "$data.v",
                                    initialValue: "",
                                    in: {
                                        $concat: [
                                            "$$value",
                                            { $cond: { if: { $eq: ["$$value", ""] }, then: "", else: ", " } },
                                            { $concat: ["'", "$$this", "'"] }
                                        ]
                                    }
                                }
                            }
                        }
                    ],
                    default: "$data.v"
                }
            },
        }
    },
    {
        $group: {
            _id: "$_id",
            section: { $addToSet: { "k": "$Question", "v": "$Answer" } }
        }
    },
    { $project: { section: { $arrayToObject: "$section" } } },
    { $replaceRoot: { newRoot: "$section" } }
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...