gpt4 book ai didi

mongodb - 将字符串字段值更改为其子字符串的最有效方法

转载 作者:可可西里 更新时间:2023-11-01 09:12:58 31 4
gpt4 key购买 nike

我有一个集合,里面装满了如下所示的文档:

{
data: 11,
version: "0.0.32"
}

有些versiontest后缀:

{
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 操作最有效?

最佳答案

最有效的方法是在撰写本文时即将发布的 MongoDB 版本中使用 $split 运算符将我们的字符串拆分为 shown here然后使用 $let 将数组中的最后一个元素分配给一个变量变量运算符和 $arrayElemAt运营商。

接下来,我们使用$switch运算符对该变量执行逻辑条件处理或case语句。

这里的条件是$gt如果值包含 "test",则返回 true,在这种情况下,在 in 表达式中,我们拆分该字符串并简单地返回 $concat新计算的数组中第一个元素的赋值和 -。如果条件计算结果为假,我们只返回变量。

当然,在我们的 case 语句中,我们使用 $indexOfCP,如果没有出现 "test",它会返回 -1

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

如您所见,“版本”字段数据是字符串。如果该字段的数据类型无关紧要,那么您可以简单地使用 $out 聚合管道阶段运算符将结果写入新集合或替换您的集合。

{ "out": "collection" }

如果您需要将数据转换为 float ,唯一的方法就是迭代聚合 Cursor 对象并使用 parseFloat 转换您的值或 Number然后使用 $set 更新您的文档运算符和 bulkWrite()最大效率的方法。

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 向后的最佳选择是 mapReduce使用 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"];

结果 如下所示:

[
{
"_id" : ObjectId("57a98773cbbd42a2156260d8"),
"value" : "32"
},
{
"_id" : ObjectId("57a98773cbbd42a2156260d9"),
"value" : "-42"
}
]

从这里您可以使用之前的 .forEach循环更新您的文档。


从 MongoDB 2.6 到 3.0,您将需要使用现已弃用的 Bulk() API 及其关联方法,如我的 answer here. 中所示

关于mongodb - 将字符串字段值更改为其子字符串的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38832525/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com