MongoDB Java - 为现有数组的每个元素创建一个新的 ObjectId
MongoDB Java - Create a new ObjectId for each element of an existing array
我有一个现有的集合,其中包含多个文档。
[{
"_id": "...1",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"value": "sub element 1.1"
},
{
"value": "sub element 1.2"
},
{
"value": "sub element 1.3"
}
]
}, {
"_id": "...2",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"value": "sub element 2.1"
},
{
"value": "sub element 2.2"
}
]
}, // many others here...
]
对于每个根文档,我想在 someArray
的每个子元素上添加类型 ObjectId
的 _id
属性。所以,在我运行我的命令之后,集合的内容如下:
[{
"_id": "...1",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"_id": ObjectId("..."),
"value": "sub element 1.1"
},
{
"_id": ObjectId("..."),
"value": "sub element 1.2"
},
{
"_id": ObjectId("..."),
"value": "sub element 1.3"
}
]
}, {
"_id": "...2",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"_id": ObjectId("..."),
"value": "sub element 2.1"
},
{
"_id": ObjectId("..."),
"value": "sub element 2.2"
}
]
}, // ...
]
当然,每个 ObjectId
都是独一无二的。
我越接近这个:
db.getCollection('myCollection').updateMany({}, { "$set" : { "someArray.$[]._id" : ObjectId() } });
但是整个集合的每个子元素最终都具有相同的 ObjectId 值...
理想情况下,我需要使用 MongoDB 的 Java 驱动程序使其工作。我得到的最接近的版本是这个(它提出了完全相同的问题:创建的所有 ObjectId 都具有相同的值)。
database
.getCollection("myCollection")
.updateMany(
Filters.ne("someArray", Collections.emptyList()), // do not update empty arrays
new Document("$set", new Document("someArray.$[el]._id", "ObjectId()")), // set the new ObjectId...
new UpdateOptions().arrayFilters(
Arrays.asList(Filters.exists("el._id", false)) // ... only when the _id property doesn't already exist
)
);
使用MongoDB v4.4+,可以使用$function
来使用javascript赋值数组中的_id。
db.collection.aggregate([
{
"$addFields": {
"someArray": {
$function: {
body: function(arr) {
return arr.map(function(elem) {
elem['_id'] = new ObjectId();
return elem;
})
},
args: [
"$someArray"
],
lang: "js"
}
}
}
}
])
这里是Mongo playground供您参考。 (与上面的代码略有不同,因为playground要求js代码用双引号)
对于旧版本的MongoDB,您需要使用javascript循环文档并逐一更新它们。
db.getCollection("...").find({}).forEach(function(doc) {
doc.someArray = doc.someArray.map(function(elem) {
elem['_id'] = new ObjectId();
return elem;
})
db.getCollection("...").save(doc);
})
这是我最后写的:
MongoCollection<Document> collection = database.getCollection("myCollection");
collection
.find(Filters.ne("someArray", Collections.emptyList()), MyItem.class)
.forEach(item -> {
item.getSomeArray().forEach(element -> {
if( element.getId() == null ){
collection.updateOne(
Filters.and(
Filters.eq("_id", item.getId()),
Filters.eq("someArray.value", element.getValue())
),
Updates.set("someArray.$._id", new ObjectId())
);
}
});
});
sub-elements 的 value
属性 必须是唯一的(幸运的是它是)。而且我必须执行单独的 updateOne
操作才能为每个元素获得不同的 ObjectId
。
我有一个现有的集合,其中包含多个文档。
[{
"_id": "...1",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"value": "sub element 1.1"
},
{
"value": "sub element 1.2"
},
{
"value": "sub element 1.3"
}
]
}, {
"_id": "...2",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"value": "sub element 2.1"
},
{
"value": "sub element 2.2"
}
]
}, // many others here...
]
对于每个根文档,我想在 someArray
的每个子元素上添加类型 ObjectId
的 _id
属性。所以,在我运行我的命令之后,集合的内容如下:
[{
"_id": "...1",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"_id": ObjectId("..."),
"value": "sub element 1.1"
},
{
"_id": ObjectId("..."),
"value": "sub element 1.2"
},
{
"_id": ObjectId("..."),
"value": "sub element 1.3"
}
]
}, {
"_id": "...2",
"prop1": "...",
"prop2": "...",
"someArray": [
{
"_id": ObjectId("..."),
"value": "sub element 2.1"
},
{
"_id": ObjectId("..."),
"value": "sub element 2.2"
}
]
}, // ...
]
当然,每个 ObjectId
都是独一无二的。
我越接近这个:
db.getCollection('myCollection').updateMany({}, { "$set" : { "someArray.$[]._id" : ObjectId() } });
但是整个集合的每个子元素最终都具有相同的 ObjectId 值...
理想情况下,我需要使用 MongoDB 的 Java 驱动程序使其工作。我得到的最接近的版本是这个(它提出了完全相同的问题:创建的所有 ObjectId 都具有相同的值)。
database
.getCollection("myCollection")
.updateMany(
Filters.ne("someArray", Collections.emptyList()), // do not update empty arrays
new Document("$set", new Document("someArray.$[el]._id", "ObjectId()")), // set the new ObjectId...
new UpdateOptions().arrayFilters(
Arrays.asList(Filters.exists("el._id", false)) // ... only when the _id property doesn't already exist
)
);
使用MongoDB v4.4+,可以使用$function
来使用javascript赋值数组中的_id。
db.collection.aggregate([
{
"$addFields": {
"someArray": {
$function: {
body: function(arr) {
return arr.map(function(elem) {
elem['_id'] = new ObjectId();
return elem;
})
},
args: [
"$someArray"
],
lang: "js"
}
}
}
}
])
这里是Mongo playground供您参考。 (与上面的代码略有不同,因为playground要求js代码用双引号)
对于旧版本的MongoDB,您需要使用javascript循环文档并逐一更新它们。
db.getCollection("...").find({}).forEach(function(doc) {
doc.someArray = doc.someArray.map(function(elem) {
elem['_id'] = new ObjectId();
return elem;
})
db.getCollection("...").save(doc);
})
这是我最后写的:
MongoCollection<Document> collection = database.getCollection("myCollection");
collection
.find(Filters.ne("someArray", Collections.emptyList()), MyItem.class)
.forEach(item -> {
item.getSomeArray().forEach(element -> {
if( element.getId() == null ){
collection.updateOne(
Filters.and(
Filters.eq("_id", item.getId()),
Filters.eq("someArray.value", element.getValue())
),
Updates.set("someArray.$._id", new ObjectId())
);
}
});
});
sub-elements 的 value
属性 必须是唯一的(幸运的是它是)。而且我必须执行单独的 updateOne
操作才能为每个元素获得不同的 ObjectId
。