Search code examples
mongodbaggregation-framework

Getting the document field names and adding them as nested fields in an Aggregation


Im writing a mongodb aggregate pipeline. My documents are of the form below :

   {
  name: "01"
  tags {
  tag_01: {
    a: "a01-val",
    b: "b01-val"
  },
  tag_02: {
    a: "a02-val",
    b: "b02-val"
  }
  }
},
{
  name: "02"
  tags {
  tag_03: {
    a: "a03-val",
    b: "b03-val"
  },
  tag_04: {
    a: "a04-val",
    b: "b04-val"
  }
  }
}

My pipeline should generate documents as below :

{
  name: "01"
  tags {
  tag_01: {
    a: "a01-val",
    b: "b01-val",
    tagName: "tag_01"
  },
  tag_02: {
    a: "a02-val",
    b: "b02-val",
    tagName: "tag_02"
  }
  }
},
{
  name: "02"
  tags {
  tag_03: {
    a: "a03-val",
    b: "b03-val",
    tagName: "tag_03"
  },
  tag_04: {
    a: "a04-val",
    b: "b04-val",
    tagName: "tag_04"
  }
  }
}

In other words, a new field is added inside each subdocument whose value is the name of the parent field. Is it possible to do this?


Solution

  • Use $objectToArray to convert tags into an array of k-v tuples. Use $map to iterate through the array elements and $mergeObjects to set the field with k. Then use $arrayToObject to revert back to original object form.

    db.collection.update({},
    [
      {
        "$set": {
          "tags": {
            "$objectToArray": "$tags"
          }
        }
      },
      {
        "$set": {
          "tags": {
            "$map": {
              "input": "$tags",
              "as": "tag",
              "in": {
                k: "$$tag.k",
                v: {
                  "$mergeObjects": [
                    "$$tag.v",
                    {
                      "tagName": "$$tag.k"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      {
        $set: {
          tags: {
            "$arrayToObject": "$tags"
          }
        }
      }
    ],
    {
      multi: true
    })
    

    Mongo Playground