Search code examples
node.jsmongodbmongodb-queryaggregation-frameworkmongodb-aggregation

Mongoose extract first subarray element after filtering


I have array in subdocument like this

    {
    "_id" : ObjectId("512e28984815cbfcb21646a7"),
    "descDay" : [
        {
            "language" : "en",
            "desc": "day description"
        },
        {
            "language" : "es",
            "desc": "descripcion del dia"
        }
    ]
}

I want to filter the subdocuments by language. I can do that like this

db.test.aggregate([
    { $project: {
        descDay: {$filter: {
            input: '$list',
            as: 'item',
            cond: {$gt: ['$$item.language', 'en']}
        }}
    }}
])

that would give me something like

{
  "_id" : ObjectId("512e28984815cbfcb21646a7"),
   "descDay" : [
      {
        "language" : "en",
        "desc": "day description"
       }]
}

but I need descDay to be a document not an array, something like this:

   {
      "_id" : ObjectId("512e28984815cbfcb21646a7"),
       "descDay" : 
          {
            "language" : "en",
            "desc": "day description"
           }
    }

how can I get that?


Solution

  • You can use $unwind to unwind the single-element descDay array into an object:

    db.test.aggregate([
        { $project: {
            descDay: {$filter: {
                input: '$descDay',
                as: 'item',
                cond: {$eq: ['$$item.language', 'en']}
            }}
        }},
        { $unwind: '$descDay' }
    ])
    

    Or, as @chridam mentioned, you can use $arrayElemAt in the $project and directly project the first element:

    db.test.aggregate([
        { $project: {descDay: {$arrayElemAt: [
            {$filter: {
                input: '$descDay',
                as: 'item',
                cond: {$eq: ['$$item.language', 'en']}
            }}, 0]
        }}}
    ])
    

    Either way the output is:

    { 
        "_id" : ObjectId("512e28984815cbfcb21646a7"), 
        "descDay" : {
            "language" : "en", 
            "desc" : "day description"
        }
    }
    

    Note that I had to fix a couple problems in your original query:

    1. '$list' to '$descDay'
    2. $gt to $eq