我们有一个称为Notes的MongoDB文档,其中包含一个Layout
部分和一个Data
部分。 Data
部分使用Layout
部分来描述和标记字段。例如,这是注释文档的简化示例:
{
"_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
部分(MappingId
s)中找到。
考虑到我们Note
文档的自我描述性质,有人可以建议一种将答案数组转换为单个文本逗号分隔值的方法吗?这真杀了我...
更新
我可能还不清楚,以上“注释”内容没有固定的字段。我不能指望在那里的SomeShortAnswerId
,SomeMultipleChoiceId
或SomeYesNoId
。这些字段可能存在,或者可能还有其他多个选择字段,以转换为CSV格式。这些都是基于Layout
部分的内容。
是否可以遍历节(Data
)中的所有字段而不必指定实际的字段名称?如果可以的话,我可以对每个字段应用$ reduce。
答案 0 :(得分:0)
根据Alex Blex的建议,我能够自由使用聚合功能$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" } }
])