Reputation: 387
I need to move an array element from one array to another array within the same document and delete the element from the original array it was moved from.
// Document
{
_id: ObjectId("67dc90594947be000838f7a7"),
persons: [
{
personId: "61cd90594947be000838f7c1",
name: "John Doe",
employment: [
{
employmentId: "61cd9059494abe000838f7c8",
type: "Full time",
salary: 1010101
}
]
},
{
personId: "61cd90594947be000838f7c2",
name: "Jane Austin",
employment: [
{
employmentId: "61cd9059494abe000738f7c1",
type: "Part time",
salary: 11011111
}
]
},
]
}
I need to move one of the employment element from John Doe to Jane Austin and both of those persons are in the same document. And I need to delete that moved element from John Doe.
employmentId
is used to identify which employment to move. And personId
is used to identify from which person to move to which person.
Example payload
const updatePayload = {
fromPerson: "61cd90594947be000838f7c1",
toPerson: "61cd90594947be000838f7c2",
employmentId: "61cd9059494abe000838f7c8",
}
Expected Result
// employment from John Doe is moved to Jane Austin
{
_id: ObjectId("67dc90594947be000838f7a7"),
persons: [
{
personId: "61cd90594947be000838f7c1",
name: "John Doe",
employment: [ ]
},
{
personId: "61cd90594947be000838f7c2",
name: "Jane Austin",
employment: [
{
employmentId: "61cd9059494abe000738f7c1",
type: "Part time",
salary: 11011111
},
{
employmentId: "61cd9059494abe000838f7c8",
type: "Full time",
salary: 1010101
}
]
},
]
}
Upvotes: 1
Views: 210
Reputation: 22276
Here is a working sample for Mongo version 4.4, our strategy will be to first match the employment
we want to move, then update each of the persons
accordingly, I will say that doing this in Mongo v5.0+ will be much cleaner as we could use $getField, this would make the first two stages of the pipelined update much simpler.
With that said here is the code sample:
const updatePayload = {
fromPerson: "61cd90594947be000838f7c1",
toPerson: "61cd90594947be000838f7c2",
employmentId: "61cd9059494abe000838f7c8",
}
db.collection.update({},
[
{
$set: {
tmpPerson: {
$arrayElemAt: [
{
$filter: {
input: "$persons",
as: "person",
cond: {
$eq: [
"$$person.personId",
updatePayload.fromPerson
]
}
}
},
0
]
}
}
},
{
$set: {
tmpEmployment: {
$arrayElemAt: [
{
$filter: {
input: "$tmpPerson.employment",
as: "employment",
cond: {
$eq: [
"$$employment.employmentId",
updatePayload.employmentId
]
}
}
},
0
]
}
}
},
{
$set: {
persons: {
$map: {
input: "$persons",
as: "person",
in: {
$switch: {
branches: [
{
case: {
$eq: [
"$$person.personId",
updatePayload.fromPerson
]
},
then: {
$mergeObjects: [
"$$person",
{
employment: {
$filter: {
input: "$$person.employment",
as: "employment",
cond: {
$eq: [
"$$employment.employmentId",
updatePayload.employmentId
]
}
}
}
}
]
}
},
{
case: {
$eq: [
"$$person.personId",
updatePayload.toPerson
]
},
then: {
$mergeObjects: [
"$$person",
{
employment: {
$concatArrays: [
"$$person.employment",
[
"$tmpEmployment"
]
]
}
}
]
}
}
],
default: "$$person"
}
}
}
}
}
},
{
$unset: [
"tmpPerson",
"tmpEmployment"
]
}
])
One last thing to note is that this pipeline assumes that the input exists properly, otherwise it will add null
to the employment array. if this is not the case then you should add some protection.
Upvotes: 1