mongodbmongodb-queryaggregation-frameworkpymongo

MongoDB: rename a field with dot in it


I have a MongoDB collection that contains several fields with dots, like:

{
    "symbol.name": "Some name"
    "symbol.state": "Some state"
    // etc.
}

Now, I need to rename "symbol.name" to just "symbol", and remove the rest of the fields that start with "symbol.". None of the methods worked so far for me. Usually, the field just stays the same, nothing changes. We are using Mongo 4.4 and pymongo.

Is there a working solution to this problem?


Solution

  • You can do the followings in an update with aggregation pipeline:

    1. $objectToArray of $$ROOT into an array of kv tuples, named kv
    2. iterate through kv by $map. In a $switch, do the followings:
      • if kv.k equals to symbol.name, remap the kv.k(i.e. field name) to symbol.name
      • check $indexOfCP of symbol. in kv.k, if it is equal to 0, $set the tuple to $$REMOVE. This will leave null in resulting mapping result array and we will handle this in step 3
      • for default case of the $switch, we can simply keep the kv entry
    3. use $filter to keep only non-null entries
    4. $replaceRoot to revert back to original object form
    db.collection.update({},
    [
      {
        "$project": {
          "kv": {
            "$objectToArray": "$$ROOT"
          }
        }
      },
      {
        "$set": {
          "kv": {
            "$map": {
              "input": "$kv",
              "as": "kv",
              "in": {
                "$switch": {
                  "branches": [
                    {
                      // handling for symbol.name
                      "case": {
                        "$eq": [
                          "symbol.name",
                          "$$kv.k"
                        ]
                      },
                      "then": {
                        k: "symbol",
                        v: "$$kv.v"
                      }
                    },
                    {
                      // remove fields starting by symbol.
                      "case": {
                        "$eq": [
                          0,
                          {
                            "$indexOfCP": [
                              "$$kv.k",
                              "symbol."
                            ]
                          }
                        ]
                      },
                      "then": "$$REMOVE"
                    }
                  ],
                  "default": "$$kv"
                }
              }
            }
          }
        }
      },
      {
        "$set": {
          // remove null fields(i.e. fields started by symbol.)
          "kv": {
            "$filter": {
              "input": "$kv",
              "as": "kv",
              "cond": {
                "$ne": [
                  "$$kv",
                  null
                ]
              }
            }
          }
        }
      },
      {
        // revert back to original object form
        "$replaceRoot": {
          "newRoot": {
            "$arrayToObject": "$kv"
          }
        }
      }
    ],
    {
      multi: true
    })
    

    Mongo Playground
    More concise version