我的收藏品中装满了这样的文件:
{
data: 11,
version: "0.0.32"
}
有些test
后缀为version
:
{
data: 55,
version: "0.0.42-test"
}
version
字段具有不同的值,但始终符合模式:0.0.XXX
。我想更新所有文档,如下所示:
{
data: 11,
version: 32
}
和后缀版本(对于测试文档 - version
应该是否定的):
{
data: 55,
version: -42
}
这些文档的集合由我们的关键系统使用,需要在更新数据时关闭 - 所以我希望更新/更改尽可能快。此集合中大约有66_000_000
个文档,大小约为100GB。
哪种类型的mongodb操作最有效?
答案 0 :(得分:4)
执行此操作的最有效方法是在撰写本文时即将发布的MongoDB版本中使用$split
运算符将字符串拆分为shown here,然后将数组中的最后一个元素指定给变量使用$let
变量运算符和$arrayElemAt
运算符。
接下来,我们使用$switch
运算符对该变量执行逻辑条件处理或case语句。
这里的条件是$gt
,如果值包含"test"
,则返回true,在这种情况下,在 in 表达式中,我们拆分该字符串并简单地返回{{ 3}}新计算数组中第一个元素的值和-
。如果条件的计算结果为false,我们只返回变量。
当然,在我们的案例陈述中,如果没有出现$indexOfCP
,我们会使用-1
返回"test"
。
let cursor = db.collection.aggregate(
[
{ "$project": {
"data": 1,
"version": {
"$let": {
"vars": {
"v": {
"$arrayElemAt": [
{ "$split": [ "$version", "." ] },
-1
]
}
},
"in": {
"$switch": {
"branches": [
{
"case": {
"$gt": [
{ "$indexOfCP": [ "$$v", "test" ] },
-1
]
},
"then": {
"$concat": [
"-",
"",
{ "$arrayElemAt": [
{ "$split": [ "$$v", "-" ] },
0
]}
]
}
}
],
"default": "$$v"
}
}
}
}
}}
]
)
聚合查询产生如下内容:
{ "_id" : ObjectId("57a98773cbbd42a2156260d8"), "data" : 11, "version" : "32" }
{ "_id" : ObjectId("57a98773cbbd42a2156260d9"), "data" : 55, "version" : "-42" }
如您所见,“version”字段数据是字符串。如果该字段的数据类型无关紧要,您只需使用$out
聚合管道阶段运算符将结果写入新集合或替换您的集合。
{ "out": "collection" }
如果你需要将数据转换为浮点数,那么,唯一的方法是,只是因为MongoDB没有提供一种方法来进行开箱即用的类型转换,除了整数到字符串,是迭代聚合Cursor对象并使用$concat
或parseFloat
转换您的值,然后使用Number
运算符和$set
方法更新您的文档,以获得最高效率。
let requests = [];
cursor.forEach(doc => {
requests.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": {
"$set": {
"data": doc.data,
"version": parseFloat(doc.version)
},
"$unset": { "person": " " }
}
}
});
if ( requests.length === 1000 ) {
// Execute per 1000 ops and re-init
db.collection.bulkWrite(requests);
requests = [];
}}
);
// Clean up queues
if(requests.length > 0) {
db.coll.bulkWrite(requests);
}
虽然聚合查询在MongoDB 3.4或更新版本中完全有效,但MongoDB 3.2向后的最佳选择是使用bulkWrite()
方法的bulkWrite()
。
var results = db.collection.mapReduce(
function() {
var v = this.version.split(".")[2];
emit(this._id, v.indexOf("-") > -1 ? "-"+v.replace(/\D+/g, '') : v)
},
function(key, value) {},
{ "out": { "inline": 1 } }
)["results"];
results
看起来像这样:
[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]
从这里开始,您可以使用上一个mapReduce
循环来更新文档。