首页 > 解决方案 > 如何更新多个文档并在 MongoDB 中添加从另一个计算的新字段?

问题描述

我有多个文档,text其中包含日期/时间字符串(例如'2020-12-14 22:43:56')或一些文本的字段。我想在所有文档中添加一个新字段,该字段将从中计算text并包含 ISODate 或 null。我有这个脚本应该这样做,它可以在投影中工作,但不适用于更新操作:

db.test.updateMany(
    {date: {$exists: false}},
    {$set: {
        date: {$dateFromString: {
                       dateString: "$text",
                       format: "%Y-%m-%d %H:%M:%S",
                       onError: null
                       }}
        
    }
    })

但它会抛出一个错误:

WriteError({
    "index" : 0,
    "code" : 52,
    "errmsg" : "The dollar ($) prefixed field '$dateFromString' in 'date.$dateFromString' is not valid for storage.",
    "op" : {
        "q" : {
            "date" : {
                "$exists" : false
            }
        },
        "u" : {
            "$set" : {
                "date" : {
                    "$dateFromString" : {
                        "dateString" : "$text",
                        "format" : "%Y-%m-%d %H:%M:%S",
                        "onError" : null
                    }
                }
            }
        },
        "multi" : true,
        "upsert" : false
    }
})

我做错了什么?这样做的正确方法是什么?

标签: mongodb

解决方案


$dateFromString是一个聚合函数,不能直接在updateMany. 幸运的是(从 MongoDB 4.2 开始)updateMany也接受一个聚合管道,而不仅仅是一个更新文档。

会是这个:

db.test.updateMany(
    {date: {$exists: false}},
    [
        {$addFields: {
           date: {$dateFromString: {
                       dateString: "$text",
                       format: "%Y-%m-%d %H:%M:%S",
                       onError: null
                       }}
          }
       }
    ]
)

$addFields只是一个别名$set- 但它可视化更新运算符$set和聚合阶段$set之间的区别

请参阅使用聚合管道进行更新


推荐阅读