MongoDB Java -使用其他字段值更新每个子数组元素



我有一个现有的集合,包含几个文档:

[{
"_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...
]

我需要将子元素的color字段替换为colors字段,这是一个包含与color相同值的数组。

下面是我想要得到的结果:

[{
"_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" ]
}
]
}]

我最接近的尝试是:

collection.updateMany(
Filters.ne("someArray", Collections.emptyList()),
Updates.combine(
Updates.set("someArray.$[].colors", "[ $someArray.color ]"),
Updates.unset("someArray.$[].color")
)
);

但是colors的值按原样作为String插入。它不会被解释为"包含color字段值的数组"。

在Java中完成。请不要提供基于js的解决方案

我终于想到了解决办法…

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")
)
);
}
});

正如评论部分所建议的,恐怕这可以通过一个简单的更新查询来完成,但是,如果您使用MongoDB version 4.2及以上,您可以使用$merge来获得优势,生成更新的文档并将其合并到现有的集合中,如下所示:

MongoClient mongoClient = new MongoClient(
new MongoClientURI(
"mongodb://localhost:27017/"
)
);
MongoDatabase database = mongoClient.getDatabase("StackOverflow");
MongoCollection<Document> collection = database.getCollection("Sample");
FindIterable<Document> result = (FindIterable<Document>) collection.aggregate(Arrays.asList(new Document("$match",
new Document("someArray",
new Document("$exists", true)
.append("$ne", Arrays.asList()))),
new Document("$unwind",
new Document("path", "$someArray")),
new Document("$set",
new Document("someArray.colors", Arrays.asList("$someArray.color"))),
new Document("$unset", "someArray.color"),
new Document("$group",
new Document("_id", "$_id")
.append("someArray",
new Document("$push", "$someArray"))),
new Document("$merge", "collection")));

这是工作,mongo shell等效管道。

最新更新