Is it possible to get a array based on the fields using aggregate?

I have the Collection with the below data.

    {
        mytoken: 'foo',
        attributes: [
            { attribute: 'Attr-A', value: 'value-for-a', op: ':=' }
            { attribute: 'Attr-B', value: 'value-for-b', op: ':=' },
            { attribute: 'Attr-C', value: 'value-for-c', op: '-=' },
            { attribute: 'Attr-D', value: 'value-for-d', op: '+=' },
            { attribute: 'Attr-E', value: 'value-for-e', op: ':=' }
        ]
    }

Therefore, I’d to get only the ‘attributes’ array result based on which attributes values I want.

e.g: I was trying something like…

// It doesn't work
[[
   {
      "$match":{
         "mytoken":"foo"
      }
   },
   {
      "$addFields":{
         "attributes.Attr-C":"$value",
         "attributes.Attr-E":"$value",
      }
   },
   {
      "$project":{
         "_id":0,
         "attributes":{
            "$objectToArray":"$attributes"
         }
      }
   },
   {
      "$unwind":"$attributes"
   },
   {
      "$project":{
         "_id":0,
         "attribute":"$attributes.k",
         "value":"$attributes.v",
         "op":"$op"
      }
   }
]]

My goal is to have a result like this:

[
   { attribute: 'Attr-C', value: 'value-for-c', op: '-=' },
   { attribute: 'Attr-E', value: 'value-for-e', op: ':=' }
]

and also a possibility to get the entire attributes: [] array.

Appreciate any help.

Note I made the assumption that $value in your sample query was passed in…

I can see two main options:

  • Match, Unwind, Match
  • Match, Filter, Unwind

This operator lets you filter an array, so we could do this:

db.getCollection("Test").aggregate([
{
    $match:{
         "mytoken":"foo"        
    }
},
{
    $project:{
        filteredArray:{
            $filter:{
                input:'$attributes',
                as:'theItem',
                cond:{$in:['$$theItem.attribute', ['Attr-B', 'Attr-A']]}
            }
        }
    }
},
{
    $unwind:'$filteredArray'
},
{
    $replaceRoot:{
        newRoot:'$filteredArray'
    }
}
])

Alternatively with the other option, you could do something like this:

db.getCollection("Test").aggregate([
{
    $match:{
         "mytoken":"foo"        
    }
},
{    
    $unwind:'$attributes'
},
{
    $match:{
        'attributes.attribute':{
            $in:[
                'Attr-B', 'Attr-A'
            ]
        }
    }
},
{
    $replaceRoot:{
        newRoot:'$attributes'
    }
}
])
1 Like

Thank you @John_Sewell

Even it it possible to get only the attributes array content?

eg: the entire attributes field:

[
            { attribute: 'Attr-A', value: 'value-for-a', op: ':=' }
            { attribute: 'Attr-B', value: 'value-for-b', op: ':=' },
            { attribute: 'Attr-C', value: 'value-for-c', op: '-=' },
            { attribute: 'Attr-D', value: 'value-for-d', op: '+=' },
            { attribute: 'Attr-E', value: 'value-for-e', op: ':=' }
]

I am showing only the attributes: [] like: Not sure if it is the more fast and better way. therefore, it is working as well.

db.Test.aggregate([
{
    $match:{
        "mytoken":"foo"    
    }
},
{    
    $unwind: '$attributes'
},
{
    $replaceRoot:{
        newRoot:'$attributes'
    }
}
])