skip to Main Content

I have a MongoDB collection containing documents like these:

   {
    "id": "62cd5de762c595905e37821b",
    "letterNo": "122233",
    "letterDate": "2023-03-01",
    "metaData": {
      "name": "test",
      "family ": "test"
     }
  },
   {
    "id": "62cd5de762c595905e37821a",
    "letterNo": "122233",
    "letterDate": "2023-03-01",
    "metaData": {
      "type": "xxxx",
      "where": "test"
     }
  }

I want to $group in metaData field as metaData_string, that every shema change to string live this:

   {
    "id": "62cd5de762c595905e37821a",
    "letterNo": "122233",
    "letterDate": "1400-03-01",
    "metaData_string":"{n'name': 'test',n'family ': 'test'n}"
  },
  {
    "id": "62cd5de762c595905e37821a",
    "letterNo": "122233",
    "letterDate": "1400-03-01",
    "metaData_string":"{n'type': 'xxxxx',n'where': 'test'n}"
  }

Is it possible using the Aggregation Framework only? I haven’t seen reference to subdocuments in the aggregation framework documentation, so I think it’s not…

Thx you all.

2

Answers


  1. You can use $function, if it’s a one-time operation, but you’ll need to enable server-side javascript. Like this:

    db.collection.aggregate([
      {
        "$addFields": {
          "metaData": {
            "$function": {
              "body": "function(obj) { return JSON.stringify(obj)}",
              "args": [
                "$$ROOT.metaData"
              ],
              "lang": "js"
            }
          }
        }
      }
    ])
    

    Playground link.

    Login or Signup to reply.
  2. Regarding the above answer due to security vulnerability such as JS injection I recommend using $map, $reduce operator to get the string result and concat them together, below is the solution I come up with that also handles the nested list of objects:

     { $project: {
       "metaData": {
         $map: {
           input: {
             $objectToArray: "$metaData"  // $map only get the array to we are converting the object to array and input it in metaData
           },
           as: "metaData",
           in: {
             $cond: {
               if: {
                 $isArray: "$$metaData.v"   // check the if value of our metadata is is array if yes check the the null value first   and use $reduce to deconstruct the array in single value
               },
               then: {
                 "customer": {
                   $reduce: {
                     input: {
                       $ifNull: [
                         "$$metaData.v",
                         []
                       ]
                     },
                     initialValue: "",
                     in: {
                       $map: {
                         input: {
                           $objectToArray: "$$this"  // as we have  inner array use another map to get the objects value  and use $toString to convert the values to string
                         },
                         as: "cdata",
                         in: {
                           $concat: [
                             {
                               $toString: "$$cdata.k"
                             },
                             "":"",
                             {
                               $toString: "$$cdata.v"
                             }
                           ]
                         }
                       }
                     }
                   }
                 },
                 
               },
               else: {      // this part  returns the non-array object values
                 $concat: [
                   "{ "",
                   "$$metaData.k",
                   "": "",
                   "$$metaData.v",
                   "" }"
                 ]
               }
             }
           }
         }
       }
     }
    }
    

    Playground_Link

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search