MongoDB(三):一些小操作


在这里插入图片描述

1、概述

大家好,我是欧阳方超,可以关注我的公众号“欧阳方超”,后续内容将在公众号首发。今天介绍一些mongodb中的小操作。

2、更新字段值

依据集合a中的字段更新另一个集合b。
假设user1集合中有如下数据:

{
  _id: ObjectId('65f907e7457c037e6a7d17a1'),
  name: 'tom',
  address: 'addresstom'
}
{
  _id: ObjectId('65f907f0457c037e6a7d17a2'),
  name: 'peter',
  address: 'addresspeter'
}
{
  _id: ObjectId('65f907f5457c037e6a7d17a3'),
  name: 'jaker',
  address: 'addressjaker'
}

集合newUser中有如下数据:

{
  _id: ObjectId('65f9063a457c037e6a7d179e'),
  oldname: 'tom',
  newname: 'tomnew'
}
{
  _id: ObjectId('65f90650457c037e6a7d179f'),
  oldname: 'peter',
  newname: 'peternew'
}
{
  _id: ObjectId('65f9065a457c037e6a7d17a0'),
  oldname: 'jaker',
  newname: 'jakernew'
}

2.1、使用out进行更新

有这样一个需求,想对user1集合中的name进行更新,依据newUser集合中的数据进行更新。可以使用下面的命令完成这种需求(注意需要谨慎使用 $out 阶段,以避免意外清空目标集合,建议将本篇后面介绍的merge更新看完弄懂之后再结合情况更新自己的mongodb库中的数据):

db.user1.aggregate([
   {
      $lookup:
         {
           from: "newUser",
           localField: "name",
           foreignField: "oldname",
           as: "matched_docs"
         }
    },
    { $unwind: "$matched_docs" },
    { $set:
       {
         "name": "$matched_docs.newname"
       }
    },
    { $out: "user1" }
])

这段代码是一个 MongoDB 的聚合操作,用于在集合 user1 中根据另一个集合 newUser 的数据更新字段 name。让我详细解释一下每个阶段的作用:
$lookup 阶段:这个阶段用于在当前集合 user1 中查找另一个集合 newUser 中与当前文档的 name 字段匹配的文档,并将匹配的结果存储在一个新的字段 matched_docs 中。
$unwind 阶段:由于 $lookup 阶段返回的结果是一个数组,使用 $unwind 阶段将数组展开,使每个匹配的文档单独处理。
$set 阶段:在这个阶段,将当前文档中的 name 字段更新为匹配文档中的 newname 字段的值。
$out 阶段:最后,使用 $out 阶段将更新后的结果写回到原始集合 user1 中,实现了根据另一个集合中的数据更新当前集合中字段的目的。
这个聚合操作利用了 MongoDB 的强大功能,通过多个阶段逐步处理数据,实现了跨集合数据更新的需求。
这些阶段是可以单独执行的,如果要看到每步发生的变化,可以单独执行以看其效果,比如只执行lookup阶段,将上面的命令简化一下:

db.user1.aggregate([
   {
      $lookup:
         {
           from: "newUser",
           localField: "name",
           foreignField: "oldname",
           as: "matched_docs"
         }
    }
])

执行结果为:

{
  _id: ObjectId('65f907e7457c037e6a7d17a1'),
  name: 'tom',
  address: 'addresstom',
  matched_docs: [
    {
      _id: ObjectId('65f9063a457c037e6a7d179e'),
      oldname: 'tom',
      newname: 'tomnew'
    }
  ]
}
{
  _id: ObjectId('65f907f0457c037e6a7d17a2'),
  name: 'peter',
  address: 'addresspeter',
  matched_docs: [
    {
      _id: ObjectId('65f90650457c037e6a7d179f'),
      oldname: 'peter',
      newname: 'peternew'
    }
  ]
}
{
  _id: ObjectId('65f907f5457c037e6a7d17a3'),
  name: 'jaker',
  address: 'addressjaker',
  matched_docs: [
    {
      _id: ObjectId('65f9065a457c037e6a7d17a0'),
      oldname: 'jaker',
      newname: 'jakernew'
    }
  ]
}

执行包含了从lookup到out阶段通过这个命令,可以根据一个集合中的特定字段值更新另一个集合中对应字段的值。
不过这样会导致user1表中多了一个字段,这是因为我们将聚合得到的所有字段都回写到了user1集合,如下:

{
  _id: ObjectId('65f907e7457c037e6a7d17a1'),
  name: 'tomnew',
  address: 'addresstom',
  matched_docs: {
    _id: ObjectId('65f9063a457c037e6a7d179e'),
    oldname: 'tom',
    newname: 'tomnew'
  }
}
{
  _id: ObjectId('65f907f0457c037e6a7d17a2'),
  name: 'peternew',
  address: 'addresspeter',
  matched_docs: {
    _id: ObjectId('65f90650457c037e6a7d179f'),
    oldname: 'peter',
    newname: 'peternew'
  }
}
{
  _id: ObjectId('65f907f5457c037e6a7d17a3'),
  name: 'jakernew',
  address: 'addressjaker',
  matched_docs: {
    _id: ObjectId('65f9065a457c037e6a7d17a0'),
    oldname: 'jaker',
    newname: 'jakernew'
  }
}

如果不想要这个多出来的字段,可以调整下更新时的命令,使用投影操作,在聚合的结果中指定不显示哪些字段:

db.user1.aggregate([
   {
      $lookup:
         {
           from: "newUser",
           localField: "name",
           foreignField: "oldname",
           as: "matched_docs"
         }
    },
    { $unwind: "$matched_docs" },
    { $set:
       {
         "name": "$matched_docs.newname"
       }
    },
    { $project: { matched_docs: 0 } },
    { $out: "user1" }
])

2.1、使用merge进行有条件更新

注意注意,当多次执行上述MongoDB聚合操作时,会导致user1集合中的数据为空,原因是在每次执行该聚合操作时,最后一个阶段{ $out: “user1” }会将结果输出到user1集合中,覆盖原有数据。这意味着每次执行该聚合操作都会清空user1集合并将新的结果写入,设想某次聚合得到的结果为空,由于user1集合已被清空,把空数据写入到空集合中,最终导致的结果就是user1集合为空。
使用 $merge 阶段来将结果与现有数据进行合并更新是一种有效的方法,可以避免使用聚合结果完全覆盖整个目标集合。以下是具体的步骤和示例代码:
创建聚合操作: 在聚合操作中,使用 $merge 阶段将聚合结果与现有数据进行合并更新。
指定目标集合和匹配条件: 在 $merge 阶段中指定目标集合和匹配条件,以确定如何将结果合并到目标集合中。
选择合适的合并选项: 在 $merge 阶段中选择适当的合并选项,如 whenMatched, whenNotMatched, pipeline, 等,以定义更新策略。
下面是一个示例代码,演示如何在 MongoDB 聚合操作中使用 $merge 阶段来将结果与现有数据进行合并更新:

db.user1.aggregate([
   {
      $lookup:
         {
           from: "newUser",
           localField: "name",
           foreignField: "oldname",
           as: "matched_docs"
         }
    },
    { $unwind: "$matched_docs" },
    
    { $set:
       {
         "name": "$matched_docs.newname"
       }
    },
    {$project:{matched_docs:0}},
    {
      $merge:
        {
          into: "user1",  // 目标集合
          on: "_id",  // 匹配条件
          whenMatched: "merge",  // 当匹配时执行合并操作
          whenNotMatched: "insert"  // 当不匹配时执行插入操作
        }
    }
])

上面的命令重复执行,user1集合中的数据只被更新一次。

2、更新字段的部分值

更改字段的部门内容,比如将字段值中包含"你好"的部分替换为"您好",可以使用下面的命令:

db.collection_name.update({},
[
  {
    $addFields: {
      field_name: {
        $replaceOne: {
          input: "$field_name",
          find: "你好",
          replacement: "您好"
        }
      }
    }
  }
],
{ multi: true }
)

更新哪个字段,将 field_name 替换为要更新的字段名称,确保将 multi: true 选项包含在更新中,以便更新所有匹配的文档。
实现效果与mysql中replace函数类似:

UPDATE 表名 SET 字段名= REPLACE( 替换前的字段值, '替换前关键字', '替换后关键字' ) WHERE 字段名 REGEXP "替换前的字段值"; 

3、总结

本篇介绍了mongodb中更新字段值的方法,这里更新字段值有两种含义,一种是依据一个集合中的数据更新另一个集合中的数据,一种是将一个集合中某个字段的值进行部分更新,希望对有相关操作的人能有所帮助。需要注意的是,由于out操作会先将目标集合清空数据, 再讲聚合结果覆盖到目标集合,所有当聚合结果可能是空的情况时要谨慎操作,一种替代方式就是使用merge操作对数据进行有条件更新。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。

  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值