I have an existing collection, containing several documents:
[{
"_id": "1",
"someArray": [
{
"_id": "1.1"
"color": "RED"
},
{
"_id": "1.2"
"color": "GREEN"
},
{
"_id": "1.3"
"color": "GREEN"
}
]
}, {
"_id": "2",
"someArray": [
{
"_id": "2.1"
"color": "WHITE"
},
{
"_id": "2.2"
"color": "BLUE"
}
]
}, // many others here...
]
I need to replace the color
field of the sub-elements by a colors
field, which is an array containing the same value color
did.
Here is the result I want to obtain:
[{
"_id": "1",
"someArray": [
{
"_id": "1.1"
"colors": [ "RED" ]
},
{
"_id": "1.2"
"colors": [ "GREEN" ]
},
{
"_id": "1.3"
"colors": [ "GREEN" ]
}
]
}, {
"_id": "2",
"someArray": [
{
"_id": "2.1"
"colors": [ "WHITE" ]
},
{
"_id": "2.2"
"colors": [ "BLUE" ]
}
]
}]
My closest attempt was this:
collection.updateMany(
Filters.ne("someArray", Collections.emptyList()),
Updates.combine(
Updates.set("someArray.$[].colors", "[ $someArray.color ]"),
Updates.unset("someArray.$[].color")
)
);
But the value of colors
is inserted as a String, as-is. It's not interpreted as "an array containing the value of color
field".
This has to be done in Java. Please don't provide JS-based solution.
The solution I finally came up with...
MongoCollection<Document> collection = database.getCollection("myCollection");
collection.find(
Filters.ne("someArray", Collections.emptyList()), MyDocumentRoot.class
).forEach(rootElement -> {
for(int i = 0; i < rootElement.getSomeArray().size(); i++){
Document document = collection.find(Filters.eq("_id", rootElement.getId())).first();
String color = document.getList("someArray", Document.class)
.get(i)
.getString("color");
collection.updateOne(
Filters.and(
Filters.eq("_id", rootElement.getId()),
Filters.eq("someArray._id", rootElement.getSomeArray().get(i).getId())
),
Updates.combine(
Updates.set("someArray.$.colors", Collections.singleton(color)),
Updates.unset("someArray.$.color")
)
);
}
});