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;
CodePudding user response:
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"
]
}
}
}
}
}
])