从 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"
.....

PlayMongo

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