I need to remove some inconsistent objects not having did,dst and den from deeply nested array , please, advice if this can be done with single update query for all documents in the collection ?
This is example of my original document:
[
{
"_id": ObjectId("5c05984246a0201286d4b57a"),
f: "x",
"_a": [
{
"_onlineStore": {}
},
{
"_p": {
"s": {
"a": {
"t": [
{
id: 1,
"dateP": "20200-09-20",
did: "x",
dst: "y",
den: "z"
},
{
id: 2,
"dateP": "20200-09-20"
}
]
},
"c": {
"t": [
{
id: 3,
"dateP": "20300-09-22",
},
{
id: 4,
"dateP": "20300-09-23",
did: "x",
dst: "y",
den: "z"
},
{
id: 5,
"dateP": "20300-09-23",
}
]
}
}
}
}
]
}
]
After the update , the document need to look as follow:
[
{
"_id": ObjectId("5c05984246a0201286d4b57a"),
f: "x",
"_a": [
{
"_onlineStore": {}
},
{
"_p": {
"s": {
"a": {
"t": [
{
id: 1,
"dateP": "20200-09-20",
did: "x",
dst: "y",
den: "z"
}
]
},
"c": {
"t": [
{
id: 4,
"dateP": "20300-09-23",
did: "x",
dst: "y",
den: "z"
}
]
}
}
}
}
]
}
]
Please, note a.t , c.t and d.t are all possible objects inside s object , but they are not compulsory in all documents so in some documents they can be missing , in other documents there can be only a.t and c.t ,but not d.t ...
@nimrod serok helped with a partial solution here:
Remove multiple elements from deep nested array with single update query
, but there is a small drawback , missing a,c, or d objects in original document do not need to appear in the resulting document as null since they do not exist and not expected:
( d.t:null and c.t:null shall not appear after the update )
CodePudding user response:
Here's one way you could do it where the field name after _p.s
could be anything. It feels a bit fragile though since all the other field names and depths need to be constant.
db.collection.update({},
[
{
"$set": {
"_a": {
"$map": {
"input": "$_a",
"as": "elem",
"in": {
"$cond": [
{"$eq": [{"$type": "$$elem._p"}, "missing"]},
"$$elem",
{
"_p": {
"s": {
"$arrayToObject": {
"$map": {
"input": {"$objectToArray": "$$elem._p.s"},
"as": "anyKey",
"in": {
"k": "$$anyKey.k",
"v": {
"t": {
"$filter": {
"input": "$$anyKey.v.t",
"as": "t",
"cond": {
"$setIsSubset": [
["did", "dst", "den"],
{
"$map": {
"input": {"$objectToArray": "$$t"},
"in": "$$this.k"
}
}
]
}
}
}
}
}
}
}
}
}
}
]
}
}
}
}
}
],
{"multi": true}
)
Try it on mongoplayground.net.