【问题标题】:Update MongoDB collection using $toLower使用 $toLower 更新 MongoDB 集合
【发布时间】:2012-03-14 12:01:01
【问题描述】:

我有一个包含用户名的现有 MongoDB 集合。用户名包含小写和大写字母。

我想更新所有用户名,使它们只包含小写字母。

我试过这个脚本,但没有用

db.myCollection.find().forEach(
 function(e) {
 e.UserName = $toLower(e.UserName);
 db.myCollection.save(e);
 }
)

【问题讨论】:

  • 没用 == 没有改变

标签: mongodb


【解决方案1】:

MongoDB 没有 $toLower 作为命令的概念。解决方案是对数据运行一个大的for 循环并单独发布更新。

您可以在任何驱动程序或 shell 中执行此操作:

db.myCollection.find().forEach(
  function(e) {
    e.UserName = e.UserName.toLowerCase();
    db.myCollection.save(e);
  }
)

您也可以用原子更新替换保存:

db.myCollection.update({_id: e._id}, {$set: {UserName: e.UserName.toLowerCase() } })

同样,您也可以从任何驱动程序中执行此操作,代码将非常相似。


编辑:雷蒙提出了一个很好的观点。 $toLower 命令确实作为聚合框架的一部分存在,但这与更新无关。更新的文档是here

【讨论】:

  • 实际上从 2.1 开始,MongoDB 确实有 $toLower 但它只是聚合框架内的一个表达式;)
  • 感谢您的信息。我最终使用 C# 编写了一个控制台应用程序,而不是试图找出 shell 的脚本。
  • 您是否测试过第二种形式($set 的原子更新)?我无法让它工作(没有显示错误,但实际上没有更新任何文档)。我是 JavaScript 新手,所以我可能只是犯了一个菜鸟错误。
  • 迟到了,但是考虑到 e.UserName 和 e._id 的值已经在内存中,是什么使更新原子与保存相比?是否只是相对于 mongo 的内部而言它是原子的?
  • @DrewR 我猜他的意思是不会破坏对任何 other 字段的更改,因为它只会更新UserName。但是,如果UserName 发生了变化,我认为这种变化将会被破坏!
【解决方案2】:

Mongo 4.2开始,db.collection.update()可以接受聚合管道,最后允许根据自己的值更新字段:

// { username: "Hello World" }
db.collection.update(
  {},
  [{ $set: { username: { $toLower: "$username" } } }],
  { multi: true }
)
// { username: "hello world" }
  • 第一部分{} 是匹配查询,过滤要更新的文档(在本例中为所有文档)。

  • 第二部分[{ $set: { username: { $toLower: "$username" } } }],是更新聚合管道(注意方括号表示使用聚合管道):

    • $set 是一个新的聚合运算符,在这种情况下会修改 "username" 的值。
    • 使用$toLower,我们将"username"的值修改为小写形式。
  • 不要忘记{ multi: true },否则只会更新第一个匹配的文档。

【讨论】:

    【解决方案3】:

    非常相似的解决方案,但这在新的 mongo 3.2 中对我有用 在 Mongo Shell 或 MongoChef 等等效数据库工具中执行以下操作!

    db.tag.find({hashtag :{ $exists:true}}).forEach(
     function(e) {
       e.hashtag = e.hashtag.toLowerCase();
       db.tag.save(e);
    });
    

    【讨论】:

      【解决方案4】:

      聚会有点晚了,但下面的答案非常适合 mongo 3.4 及更高版本 首先只获取那些具有不同大小写的记录,然后只批量更新这些记录。 此查询的性能好几倍

      var bulk = db.myCollection.initializeUnorderedBulkOp();
      var count = 0
      db.myCollection.find({userId:{$regex:'.*[A-Z]'}}).forEach(function(e) {
       var newId = e.userId.toLowerCase();   
          bulk.find({_id:e._id}).updateOne({$set:{userId: newId}})
          count++
          if (count % 500 === 0) {
              bulk.execute();
              bulk = db.myCollection.initializeUnorderedBulkOp();
              count = 0;
          }
      })
      if (count > 0)  bulk.execute();
      

      【讨论】:

        【解决方案5】:

        使用公认的解决方案,我知道对元素数组执行相同操作非常简单,以防万一

        db.myCollection.find().forEach(
           function(e) {
              for(var i = 0; i < e.articles.length; i++) { 
                  e.articles[i] = e.articles[i].toLowerCase(); 
              }
              db.myCollection.save(e); 
           }
        )
        

        【讨论】:

          【解决方案6】:

          只需注意确保您的收藏中的所有条目都存在该字段。如果不是,您将需要一个 if 语句,如下所示:

          if (e.UserName) e.UserName = e.UserName.toLowerCase();
          

          【讨论】:

          • 你的意思是if (e.UserName)而不是if (e.username)
          猜你喜欢
          • 2014-08-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-10
          相关资源
          最近更新 更多