Search code examples
mongodbaggregation-frameworkprojection

Projecting array values in mongo document based on non array fields


The data in my database is as follows:

/* 1 */
{
      "name": "Severus",
      "u_name": "severussnape",
      "info": [
        {
          "value": "Severus",
          "source": "1",
          "infotag": "name"
        },
        {
          "value": "severussnape",
          "source": "2",
          "infotag": "name"
        }
      ]
}

/* 2 */
{
      "name": "Harry",
      "u_name": null,
      "info": [
        {
        "value": "Harry",
          "source": "1",
          "infotag": "name"
        }
      ]
}

I'd like to project the data so that the name field and the info array in the result are changed based on whether or not the u_name field is null. The result I expect looks like so:

/* 1 */
{
      "name": "severussnape",
      "info": [
        {
          "value": "severussnape",
          "source": "2",
          "infotag": "name"
        }
      ]
}

/* 2 */
{
      "name": "Harry",      
      "info": [
        {
          "value": "Harry",
          "source": "1",
          "infotag": "name"
        }
      ]
}

I've managed to project the name field correctly using the projection:

db.database.aggregate([{
    $project:{
        "name":{$cond:[{$eq:["$u_name",null]},"$name","$u_name"]}
    }
}])

But I've been unable to figure out how to remove the array element from info with value "Severus" in the first document depending on u_name. Is this possible?


Solution

  • You should try this aggregate query, this will solve your problem.

    db.database.aggregate([
        {
            $project:{
                'name': {
                    '$ifNull': ['$u_name', '$name']
                },
                'info': '$info'
            }
        },
        {
            $project: {
                'name': '$name',
                'info': {
                    '$filter': {
                        'input': '$info',
                        'as': 'info',
                        'cond': {
                            '$eq':['$$info.value', '$name']
                        }
                    }
                }
            }
        }
    ])