I’m trying to make a migration for a database, which has the following structure as of now:
{ "site" : { "name" : "siteName1" }, "subStages" : [ "subStage1", "subStage2" ] }
There have been some changes in how we need to handle a site, having now the possibility to have multiple sites, and not only one.
So I need to change the DB to look like this:
{ "sites" : [ { "name" : "siteName1", "subStages" : [ "subStage1", "subStage2" ] }, { "name" : "siteName2" } ] }
Is there a way to change the schema with a simple migration script to have each site inside a ‘sites’ array?
Any help would be appreciated.
I can share more information if needed.
EDIT:
The structure where the site is an object, inside nested objects as follows:
Object1: { stages: [ { stage1: { attributes } . . . stageINeed: { add sites ---> sites: [ ] } }
How can I access this specific stage I need?
EDIT 2: Full structure:
The collection ‘tickets’ will have numerous entries of tickets, whose structure for all needs to be changed to what we talked about before. The specific structure is as follows:
{ "_id" : ObjectId("62bf0b8b4feee27711d65e0f"), "files" : [], "stages" : [ { "name" : "Documents", "updatedAt" : ISODate("2022-07-01T14:58:19.108Z"), "state" : "none" }, . . . { "name" : "Registry", "state" : "none", "subStages" : [ { "name" : "name1", "completed" : false }, { "name" : "name2", "completed" : false }, { "name" : "name3", "completed" : false } ], "updatedAt" : ISODate("2022-07-01T14:58:19.108Z"), } ] }
The structure I want to map is the following:
{ "_id" : ObjectId("62e9219dfacb4b96823af822"), "files" : [], "stages" : [ { "name" : "Documents", "updatedAt" : ISODate("2022-07-01T14:58:19.108Z"), "state" : "none" }, . . . { "name" : "Registry", "state" : "none", "sites" : [ { "name" : "site1", "completed" : false, "status" : "none", "subStages" : [ { "name" : "name1", "completed" : false }, { "name" : "name2", "completed" : false }, { "name" : "name3", "completed" : false } ] } ], "updatedAt" : ISODate("2022-08-02T13:07:41.688Z"), } ], }
This is because future tickets will have two sites, so I want to change the structure of the existing ones to a sites configuration. Now, inside the ticket I don’t have anything that says ‘site’, I get everything from another database called configuration.
So far I have the following, but I don’t know if it’s correct:
const configSite= config.find(stage => stage.type === "Registry")?.site; const tickets = await this.tickets.updateMany( { "stages.type": "Registry" }, [ { $replaceRoot: { newRoot: { name: "$stages.name", state: "$stages.state", updatedAt: "$stages.updatedAt", type: "$stages.type", sites: [ { name: configSite.name, subStages: configSite.subStages }, ], }, }, }, ], { multi: false, upsert: false, } ); return tickets;
Advertisement
Answer
Yes, you can do this in a single update using pipelined updates and $replaceRoot, like so:
db.collection.updateMany({}, [ { $replaceRoot: { newRoot: { _id: "$_id", sites: [ { name: "$site.name", substages: "$subStages" } ] } } } ])
EDIT
Here’s how to do it for the full structure you provided, I had to make some assumptions as some things weren’t exactly clear. For example a “stage” that has the “substages” field will be converted, others will not per you sample.
db.collection.updateMany({}, [ { $set: { stages: { $map: { input: { $ifNull: [ "$stages", [] ] }, in: { $cond: [ "$$this.subStages", { name: "$$this.name", state: "$$this.state", sites: [ { //where should this come from, status: "$$this.state", completed: { $allElementsTrue: "$$this.subStages.completed" }, //where should this come from, name: "site1", subStages: "$$this.subStages" } ] }, "$$this" ] } } } } } ])