1

I have a below mongo collection "test" which does not have "tags" field on top level of the document.

{
    "_id" : 1,
    "title" : "123 Department Report",
    "year" : 2014,
    "subsections" : [
        {
            "subtitle" : "Section 1: Overview",
            "tags" : "SI",
            "content" : "Section 1: This is the content of section 1."
        },
        {
            "subtitle" : "Section 2: Analysis",
            "tags" : "STLW",
            "content" : "Section 2: This is the content of section 2."
        },
        {
            "subtitle" : "Section 3: Budgeting",
            "tags" : "TK",
            "content" : {
                "text" : "Section 3: This is the content of section3.",
                "tags" : "HCS"
            }
        }
    ]
}

My requirement is to select subsections having only "tags" value "STLW". I am running following aggregation query.

db.test.aggregate([
  { $redact: {
       $cond: {          
          if: { $or: [ {$ifNull: ['$tags', true]}, {$eq: [ "$tags" , 'STLW' ]} ] },
          then: "$$DESCEND",
          else: "$$PRUNE"
        }
      }
  }
]

However on running query I am getting all the sub documents in the below output:

{
    "_id" : 1,
    "title" : "123 Department Report",
    "year" : 2014,
    "subsections" : [
        {
            "subtitle" : "Section 1: Overview",
            "tags" : "SI",
            "content" : "Section 1: This is the content of section 1."
        },
        {
            "subtitle" : "Section 2: Analysis",
            "tags" : "STLW",
            "content" : "Section 2: This is the content of section 2."
        },
        {
            "subtitle" : "Section 3: Budgeting",
            "tags" : "TK",
            "content" : {
                "text" : "Section 3: This is the content of section3.",
                "tags" : "HCS"
            }
        }
    ]
}

However, I want the below output.

{
    "_id" : 1,
    "title" : "123 Department Report",
    "year" : 2014,
    "subsections" : 
        {
            "subtitle" : "Section 2: Analysis",
            "tags" : "STLW",
            "content" : "Section 2: This is the content of section 2."
        }
}

Can any one help me in achieving this ?

thanks...........

glytching
  • 44,936
  • 9
  • 114
  • 120
Ravi
  • 173
  • 1
  • 10
  • Possible duplicate of [How to filter array in subdocument with MongoDB](https://stackoverflow.com/questions/15117030/how-to-filter-array-in-subdocument-with-mongodb) – s7vr Aug 29 '17 at 00:08

1 Answers1

1

maybe a little late for this now, but in case anyone else still looking for something similar.

If you have Mongo 3.4, you can easily achieve this with the $filter operator and the $addFields stage. If you have 3.2, you will just need to add a projection to all the original fields (instead of using the addFields shortcut).

db.test.aggregate([
{
    $addFields:{
        subsections:{
            $filter:{
                input:"$subsections",
                cond: {$eq:["$$this.tags","STLW"]}
            }
        }
    }
}
])

will produce this response:

{
    "_id" : 1,
    "title" : "123 Department Report",
    "year" : 2014,
    "subsections" : [ 
        {
            "subtitle" : "Section 2: Analysis",
            "tags" : "STLW",
            "content" : "Section 2: This is the content of section 2."
        }
    ]
}

alternatively, if you want to keep using $redact:

db.test.aggregate([
{$redact:{
    $cond: {
        if: {
            $and:[
                {$ifNull:["$tags",false]},
                {$ne:["$tags","STLW"]}
            ]
        },
        then: "$$PRUNE",
        else: "$$DESCEND"
    }
}}
]);
Hachi
  • 11
  • 2
  • First, welcome to StackOverflow! Second, thank you for taking the time to answer this question because your answer is exactly what I was looking for. I've come to the conclusion that `$redact` is useful when the document is designed with redaction in mind. In other words, it's difficult to apply `$redact` to an existing collection not initially intended for redaction. We recently (within the last week) upgraded from MongoDB v2.6 to v3.6 and I wasn't aware of `$filter`...thank you for the excellent example! – Paul May 02 '18 at 15:53