从 Mongodb 中的字符串中删除重复字符
Remove Duplicate character from string in Mongodb
我想从 MongoDB 中的字符串中删除重复的字符。
例子:
输入字符串:xxxyzzxcdv
输出字符串:xyzcdv
查询
- 减少范围(计数字符串)
- 保留2个值
{"previous": [], "string": ""}
(reduce的初始值)
- 获取当前字符
{"$substrCP": ["$mystring", "$$this", 1]}
这是字符串的当前索引,我取下一个 char
- 如果它在之前的kep
"string"
中,否则concat
添加新字符
heelo
reduce on (0 1 2 3 4) `{"$range": [0, {"$strLenCP": "$mystring"}]}`
we start from `{"previous": [], "string": ""}`
- get 1 character start from index 0
`{"$substrCP": ["$mystring", "$$this", 1]}}` = "h"
- if this character is on previous don't add it
`{"$in": ["$$cur_char", "$$value.previous"]}`
- else add it on previous and on the string the 2 concats in code
Repeat for `index($$this)`= 1
- get 1 character start from index 1
`{"$substrCP": ["$mystring", "$$this", 1]}}` = "e"
.....
aggregate(
[{"$set":
{"mystring":
{"$getField":
{"field": "string",
"input":
{"$reduce":
{"input": {"$range": [0, {"$strLenCP": "$mystring"}]},
"initialValue": {"previous": [], "string": ""},
"in":
{"$let":
{"vars": {"cur_char": {"$substrCP": ["$mystring", "$$this", 1]}},
"in":
{"$cond":
[{"$in": ["$$cur_char", "$$value.previous"]},
"$$value",
{"previous":
{"$concatArrays": ["$$value.previous", ["$$cur_char"]]},
"string":
{"$concat": ["$$value.string", "$$cur_char"]}}]}}}}}}}}}])
编辑
第二个查询仅删除了我们选择的重复项。
查询
- 只移除数组中的字符,这里只移除["x"]
- 我删除了
$getField
因为它只适用于 MongoDB 5 +
aggregate(
[{"$set":
{"mystring":
{"$reduce":
{"input": {"$range": [0, {"$strLenCP": "$mystring"}]},
"initialValue": {"previous": [], "string": ""},
"in":
{"$let":
{"vars": {"cur_char": {"$substrCP": ["$mystring", "$$this", 1]}},
"in":
{"$cond":
[{"$and":
[{"$in": ["$$cur_char", "$$value.previous"]},
{"$in": ["$$cur_char", ["x"]]}]},
"$$value",
{"previous":
{"$concatArrays": ["$$value.previous", ["$$cur_char"]]},
"string":
{"$concat": ["$$value.string", "$$cur_char"]}}]}}}}}}},
{"$set": {"mystring": "$mystring.string"}}])
编辑
如果您需要使用此聚合进行更新,您可以将其用作管道更新。
update({},
[{"$set": ......])
请查看您的驱动程序以了解如何使用管道进行更新,在 Java 中与上面类似,替代方法 运行 为 database command
假设我们有以下集合和其中的记录:
db.messages.insertMany([
{
"message": "heelllo theeere"
},
{
"message": "may thhhee forrrce be wiithh yyouuu"
},
{
"message": "execute orrrrdder 66"
}
])
由于不确定性,我放弃了在查询时进行操作和更新记录(永久)的解决方案.
如果您想在 运行 聚合查询时删除它们:
除了@Takis 的解决方案,如果您的 MongoDB 版本是 4.4 或更高版本,使用 $function
管道运算符可能是另一种选择。
Further readings on $function operator
// Query via Aggregation Framework
db.messages.aggregate([
{
$match: {
message: {
$ne: null
}
}
},
{
$addFields: {
distinctChars: {
$function: {
body: function (message) {
return message
.split("")
.filter(function (item, pos, self) {
return self.indexOf(item) == pos;
})
.join("");
},
args: ["$message"],
lang: "js"
}
}
}
},
])
如果您想通过更新操作删除它们:
// Update each document using cursor
db.messages.find({ message: { $ne: null } })
.forEach(doc => {
var distinctChars = doc.message
.split("")
.filter(function (item, pos, self) {
return self.indexOf(item) == pos;
})
.join("");
db.messages.updateOne({ _id: doc._id }, [{ $set: { distinctChars: distinctChars } }]);
});
快速提醒:上面的脚本只是展示了一种更新记录以达到目标的简单方法,而无需关注其他细节。这可能是一项昂贵的操作,具体取决于您现实世界中集合的大小和配置,例如分片。考虑用自己的方式改进一下。
结果
对于这两种方式,结果应该如下所示:
[
{
"_id": {
"$oid": "618d95ccdedc26d80875b75a"
},
"message": "heelllo theeere",
"distinctChars": "helo tr"
},
{
"_id": {
"$oid": "618d95ccdedc26d80875b75b"
},
"message": "may thhhee forrrce be wiithh yyouuu",
"distinctChars": "may theforcbwiu"
},
{
"_id": {
"$oid": "618d95ccdedc26d80875b75c"
},
"message": "execute orrrrdder 66",
"distinctChars": "excut ord6"
}
]
我想从 MongoDB 中的字符串中删除重复的字符。 例子: 输入字符串:xxxyzzxcdv 输出字符串:xyzcdv
查询
- 减少范围(计数字符串)
- 保留2个值
{"previous": [], "string": ""}
(reduce的初始值) - 获取当前字符
{"$substrCP": ["$mystring", "$$this", 1]}
这是字符串的当前索引,我取下一个 char - 如果它在之前的kep
"string"
中,否则concat
添加新字符
heelo
reduce on (0 1 2 3 4) `{"$range": [0, {"$strLenCP": "$mystring"}]}`
we start from `{"previous": [], "string": ""}`
- get 1 character start from index 0
`{"$substrCP": ["$mystring", "$$this", 1]}}` = "h"
- if this character is on previous don't add it
`{"$in": ["$$cur_char", "$$value.previous"]}`
- else add it on previous and on the string the 2 concats in code
Repeat for `index($$this)`= 1
- get 1 character start from index 1
`{"$substrCP": ["$mystring", "$$this", 1]}}` = "e"
.....
aggregate(
[{"$set":
{"mystring":
{"$getField":
{"field": "string",
"input":
{"$reduce":
{"input": {"$range": [0, {"$strLenCP": "$mystring"}]},
"initialValue": {"previous": [], "string": ""},
"in":
{"$let":
{"vars": {"cur_char": {"$substrCP": ["$mystring", "$$this", 1]}},
"in":
{"$cond":
[{"$in": ["$$cur_char", "$$value.previous"]},
"$$value",
{"previous":
{"$concatArrays": ["$$value.previous", ["$$cur_char"]]},
"string":
{"$concat": ["$$value.string", "$$cur_char"]}}]}}}}}}}}}])
编辑
第二个查询仅删除了我们选择的重复项。
查询
- 只移除数组中的字符,这里只移除["x"]
- 我删除了
$getField
因为它只适用于 MongoDB 5 +
aggregate(
[{"$set":
{"mystring":
{"$reduce":
{"input": {"$range": [0, {"$strLenCP": "$mystring"}]},
"initialValue": {"previous": [], "string": ""},
"in":
{"$let":
{"vars": {"cur_char": {"$substrCP": ["$mystring", "$$this", 1]}},
"in":
{"$cond":
[{"$and":
[{"$in": ["$$cur_char", "$$value.previous"]},
{"$in": ["$$cur_char", ["x"]]}]},
"$$value",
{"previous":
{"$concatArrays": ["$$value.previous", ["$$cur_char"]]},
"string":
{"$concat": ["$$value.string", "$$cur_char"]}}]}}}}}}},
{"$set": {"mystring": "$mystring.string"}}])
编辑
如果您需要使用此聚合进行更新,您可以将其用作管道更新。
update({},
[{"$set": ......])
请查看您的驱动程序以了解如何使用管道进行更新,在 Java 中与上面类似,替代方法 运行 为 database command
假设我们有以下集合和其中的记录:
db.messages.insertMany([
{
"message": "heelllo theeere"
},
{
"message": "may thhhee forrrce be wiithh yyouuu"
},
{
"message": "execute orrrrdder 66"
}
])
由于不确定性,我放弃了在查询时进行操作和更新记录(永久)的解决方案.
如果您想在 运行 聚合查询时删除它们:
除了@Takis 的解决方案,如果您的 MongoDB 版本是 4.4 或更高版本,使用 $function
管道运算符可能是另一种选择。
Further readings on $function operator
// Query via Aggregation Framework
db.messages.aggregate([
{
$match: {
message: {
$ne: null
}
}
},
{
$addFields: {
distinctChars: {
$function: {
body: function (message) {
return message
.split("")
.filter(function (item, pos, self) {
return self.indexOf(item) == pos;
})
.join("");
},
args: ["$message"],
lang: "js"
}
}
}
},
])
如果您想通过更新操作删除它们:
// Update each document using cursor
db.messages.find({ message: { $ne: null } })
.forEach(doc => {
var distinctChars = doc.message
.split("")
.filter(function (item, pos, self) {
return self.indexOf(item) == pos;
})
.join("");
db.messages.updateOne({ _id: doc._id }, [{ $set: { distinctChars: distinctChars } }]);
});
快速提醒:上面的脚本只是展示了一种更新记录以达到目标的简单方法,而无需关注其他细节。这可能是一项昂贵的操作,具体取决于您现实世界中集合的大小和配置,例如分片。考虑用自己的方式改进一下。
结果
对于这两种方式,结果应该如下所示:
[
{
"_id": {
"$oid": "618d95ccdedc26d80875b75a"
},
"message": "heelllo theeere",
"distinctChars": "helo tr"
},
{
"_id": {
"$oid": "618d95ccdedc26d80875b75b"
},
"message": "may thhhee forrrce be wiithh yyouuu",
"distinctChars": "may theforcbwiu"
},
{
"_id": {
"$oid": "618d95ccdedc26d80875b75c"
},
"message": "execute orrrrdder 66",
"distinctChars": "excut ord6"
}
]