You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将正则匹配的unset逻辑移入MongoDB更新管道?

问题描述

给定简化后的Timesheets数组(实际包含70+字段):

const timesheets = [
  { "_id": "123", "WORKDATE": "2023-06-06", "ACTIVITY": 0 },
  { "_id": "456", "WORKDATE": "0000-00-00", "ACTIVITY": 5 }
]

目前通过JavaScript批量更新实现两个目标:

  1. 移除值为空字符串、空数组或0的字段(已通过$replaceRoot步骤实现)
  2. 移除值为'0000-00-00'且字段名匹配正则/(DAT|LAST|AT|FIN|START)/的字段(当前通过JS的unset函数筛选字段名,再传入管道的$unset操作)

当前的批量更新代码如下:

const handleWindow = (async (timesheets) => {
  if(!Array.isArray(timesheets) || timesheets.length === 0) return;

  const unset = (obj) => (
      // 返回需要在管道中unset的字段名数组
      Object.entries(obj).filter(([key, value]) => ( 
          value === '0000-00-00' && /(DAT|LAST|AT|FIN|START)/.test(key) 
      )).map((a) => a.shift())
  );
  
  // 批量更新/插入工时表,移除空值
  const bulkOperations = timesheets.map(timesheet => ({
      updateOne: { 
          filter: { _id: timesheet._id }, 
          update: [
              { $set: timesheet },
              { $replaceRoot: { newRoot: { $arrayToObject: {
                  $filter: { input: { $objectToArray: '$$ROOT' }, 
                  cond: { $not: { $in: ['$$this.v', ['', [], 0] ]}} }}}}},
            { $unset: unset(timesheet) }
          ], upsert: true } }
      ));        

      return await context.services.get('mongodb-atlas').db('TimesheetsDB').collection('Timesheets').bulkWrite(bulkOperations);

  })(timesheets)

想咨询两个问题:

  • 如何将上述unset的筛选逻辑直接移入MongoDB的更新管道中?
  • MongoDB管道中是否存在类似JavaScript里RegExp.test()的正则匹配方法?

解决方案

1. MongoDB管道中的正则匹配方法

MongoDB提供了$regexMatch操作符,功能和JavaScript的RegExp.test()完全一致,用于判断字符串是否匹配指定正则表达式,返回布尔值。

2. 将unset逻辑整合到更新管道中

可以把两个字段移除逻辑合并到同一个$replaceRoot步骤里,不需要单独的$unset操作。核心思路是在$filter的条件中同时排除两种字段:

  • 值为空字符串、空数组或0的字段
  • 值为'0000-00-00'且字段名匹配指定正则的字段

修改后的更新管道如下:

const bulkOperations = timesheets.map(timesheet => ({
    updateOne: { 
        filter: { _id: timesheet._id }, 
        update: [
            { $set: timesheet },
            { 
                $replaceRoot: { 
                    newRoot: { 
                        $arrayToObject: {
                            $filter: { 
                                input: { $objectToArray: '$$ROOT' }, 
                                cond: {
                                    $and: [
                                        // 排除值为空、空数组或0的字段
                                        { $not: { $in: ['$$this.v', ['', [], 0] ]}},
                                        // 排除值为'0000-00-00'且字段名匹配正则的字段
                                        { $not: {
                                            $and: [
                                                { $eq: ['$$this.v', '0000-00-00'] },
                                                { $regexMatch: { input: '$$this.k', regex: /(DAT|LAST|AT|FIN|START)/ } }
                                            ]
                                        }}
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        ], upsert: true 
    }
}));

逻辑说明

  • $objectToArray:把当前文档转换成键值对数组(每个元素是{k: 字段名, v: 字段值})
  • $filter:遍历这个数组,只保留满足条件的元素:
    1. 字段值不在['', [], 0]集合中
    2. 不同时满足「字段值是'0000-00-00'」和「字段名匹配指定正则」
  • $arrayToObject:把过滤后的键值对数组重新转换成文档
  • $replaceRoot:用这个新文档替换原文档,完成字段移除

验证示例数据效果

对于示例中的两个文档:

  • _id: "123":ACTIVITY值为0会被移除,WORKDATE值正常保留,最终文档是{ "_id": "123", "WORKDATE": "2023-06-06" }
  • _id: "456":WORKDATE值为'0000-00-00'且字段名包含DAT,会被移除,ACTIVITY值保留,最终文档是{ "_id": "456", "ACTIVITY": 5 }

内容的提问来源于stack exchange,提问作者Mikael G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 22:35:42