Move object list to an another object inside the same document

I have this document:

 {
    _id: ObjectId("63e359b9199e6d59b4495a8b"),
    email: 'user-19@gmail.com',
    firstName: 'Name19',
    lastName: 'Last19',
    sendUpdates: true,
    roles: [ 'ROLE_USER' ],
    groupEntries: [
      {
        group: DBRef("Groups", ObjectId("63e359b7199e6d59b4495a77")),
        experation: ISODate("2023-01-19T08:13:44.079Z"),
        inception: ISODate("2023-02-08T08:13:44.080Z")
      },
      {
        group: DBRef("Groups", ObjectId("63e359b7199e6d59b4495a74")),
        experation: ISODate("2024-02-08T08:13:44.069Z"),
        inception: ISODate("2023-02-08T08:13:44.069Z")
      }
    ],
    applications: [],
    accountStatus: 'active',
    registrationDate: ISODate("2019-06-25T05:43:44.088Z"),
    name: 'User-19',
    _class: 'MongoUser',
    agreement: [
      {
        agreementLevel: 'LEVEL',
        agreementType: 'USER',
        transactionDate: '$$NOW',
        validDate: 'null',
        expiredDate: 'null',
        revokedDate: 'null',
        ownAgreement: 'null'
      }
    ]
  }
]

I want to move groupEntries inside the first element of agreement. With a result like this:

 {
    _id: ObjectId("63e359b9199e6d59b4495a8b"),
    email: 'user-19@gmail.com',
    firstName: 'Name19',
    lastName: 'Last19',
    sendUpdates: true,
    roles: [ 'ROLE_USER' ],
    applications: [],
    accountStatus: 'active',
    registrationDate: ISODate("2019-06-25T05:43:44.088Z"),
    name: 'User-19',
    _class: 'MongoUser',
    agreement: [
      {
        agreementLevel: 'LEVEL1',
        agreementType: 'USER',
        transactionDate: '$$NOW',
        validDate: 'null',
        expiredDate: 'null',
        revokedDate: 'null',
        ownAgreement: 'null',
        groupEntries: [
      {
        group: DBRef("Groups", ObjectId("63e359b7199e6d59b4495a77")),
        experation: ISODate("2023-01-19T08:13:44.079Z"),
        inception: ISODate("2023-02-08T08:13:44.080Z")
      },
      {
        group: DBRef("Groups", ObjectId("63e359b7199e6d59b4495a74")),
        experation: ISODate("2024-02-08T08:13:44.069Z"),
        inception: ISODate("2023-02-08T08:13:44.069Z")
      }
    ]
      }
    ]
  }
]

My mongo server version is 4.2.0

Thank you!

With the aggregation framework you can do it.

/* The first stage extract the first element of agreement into a temp. field
*/
first_element = { "$set" : {
    "_tmp.first_element" : { "$arrayElemAt" : [ "$agreement" , 0 ] }
} }

/* The second stage extract the rest of the agreement array into a temp. field
*/
rest_of_array = { "$set" : {
    "_tmp.rest_of_array" : { "$slice" : [ "$agreement" , 1 , { "$size" : "$agreement" } ] }
} }

/* The next stage add the groupEntries field to the temp. _first_element 
*/
set_groupEntries = { "$set" : {
    "_tmp.first_element.groupEntries" : "$groupEntries"
} }

/* The following stage reconstruct the array from the modified _first_element
   and the _rest_of_array */
set_agreement = { "$set" : {
    "agreement" : { "$concatArrays" : [ [ "$_tmp.first_element" ] , "$_tmp.rest_of_array" ] }
} }

/* A final cleanup to remove the temp. fields */
cleanup = { "$unset" : "_tmp" } 

pipeline = [ first_element , rest_of_array , set_groupEntries , set_agreement , cleanup ]

If you want to store back the result in the collection use $merge stage.

You could do the above in a single stage without _tmp fields but it is easier to develop, debug and understand this way because we can see the result of each little stages.

Divide and Conquer

1 Like

Thank you very much!

I’m very new in mongodb, I am not able to store the result in the collection using $merge stage. Can you help me, please?

Thank you again!

The $merge will look something like

merge = { "$merge" : {
    "into" : "The-Name-Of-Your-Collection" ,
    "on" : "_id" ,
    "whenMatched" : "replace"
} }

I couldn’t store the result with $merge stage.
Finally, I was able to save them by doing an updateMany:
db.Users.updateMany({},pipeline)

Thank you very much!

I am not too sure but the real solution is the pipeline rather than the fact you used the pipeline in updateOne.

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.