I have an aggregation query that returns array of questions with different schema depending on type of document. The documents are in the following format. Some questions may look like this
{
"_id": "ID01",
"Description": "1.Any Question?",
"answer": { "option05": "E. " },
"options": {
"option01": "A.",
"option02": "B.",
"option03": "C.",
"option04": "D.",
"option05": "E."
},
"type": "1",
"score": 10
},
and some questions have the following structure
{
"_id": "ID02",
"Description": "Question Description.",
"emq": {
"emq3": {
"answer": "option12",
"explanation": "",
"question": "1 Any Qstn?"
},
"emq4": {
"answer": "option03",
"explanation": "",
"question": "2 Any Qstn?"
},
"emq5": {
"answer": "option06",
"explanation": "",
"question": "3 Any Qstn?"
}
},
"options": {
"option01": "",
"option02": "",
"option03": "",
"option04": "",
},
"type": "2",
"score": 100
},
I have used the following aggregation pipeline for hiding answers in the questions, (the schema in question is migrated and I cannot change its structure)
Aggregation pipeline
{
$lookup: {
from: 'questions',
let: {
question_id: { $toObjectId: '$qId' },
score: '$score',
},
pipeline: [
{
$match: {
$expr: {
$eq: ['$_id', '$$question_id'],
},
},
},
{
$project: {
answer: {
$cond: {
if: { $eq: ['$type', '1'] },
then: 0,
else: {
$cond: {
if: { $eq: ['$type', '3'] },
then: {
$cond: {
if: {
emq: {
regex: /^emq\d $/,
},
},
then: 0,
else: 1,
},
},
else: 1,
},
},
},
},
Description: 1,
options: 1,
type: 1,
emq: 1,
score: 1,
},
},
}
It works for questions that are of type 1 but unfortunately I am unable to hide answers for type 2 given the fact that they are not only within 'emq' object but also within nested 'emq3' object with dynamic numbers at the end of string 'emq', I applied regex but somehow I am unable to project answer within emq3 object, is there anyway to achieve the following result that hides answers from both questions like this
{
"_id": "ID01",
"Description": "1.Any Question?",
"options": {
"option01": "A.",
"option02": "B.",
"option03": "C.",
"option04": "D.",
"option05": "E."
},
"type": "1",
"score": 10
},
{
"_id": "ID02",
"Description": "Question Description.",
"emq": {
"emq3": {
"question": "1 Any Qstn?"
},
"emq4": {
"question": "2 Any Qstn?"
},
"emq5": {
"question": "3 Any Qstn?"
}
},
"options": {
"option01": "",
"option02": "",
"option03": "",
"option04": "",
},
"type": "2",
"score": 100
},
CodePudding user response:
You can do the followings in an aggregation pipeline:
- convert the object
emq
into an array of k-v tuple using$objectToArray
$project
to remove the fieldanswer
andexplanation
convert the array
emq` back to object
db.collection.aggregate([
{
"$addFields": {
"emq": {
"$objectToArray": "$emq"
}
}
},
{
"$project": {
"emq.v.answer": false,
"emq.v.explanation": false,
"answer": false
}
},
{
"$addFields": {
"emq": {
"$arrayToObject": "$emq"
}
}
},
{
"$addFields": {
emq: {
"$cond": {
"if": {
$eq: [
"$emq",
null
]
},
"then": "$$REMOVE",
"else": "$emq"
}
}
}
}
])
Here is the Mongo playground for your reference.