本机 MongoDB:为啥我的 switch 语句不能使用字段名称,而只能使用硬编码值?

Posted

技术标签:

【中文标题】本机 MongoDB:为啥我的 switch 语句不能使用字段名称,而只能使用硬编码值?【英文标题】:Native MongoDB: Why is my switch statement not working with field names but only hard coded values?本机 MongoDB:为什么我的 switch 语句不能使用字段名称,而只能使用硬编码值? 【发布时间】:2022-01-22 01:17:32 【问题描述】:

问题:我试图找到一种仅更新我的 lastModified 字段的方法,如果用户输入的字段值在更新时实际发生变化。最初,我将 lastModified 字段包含在(非聚合)$set 对象中,即使其他更新字段没有,它也总是在 new Date() 更改时更新它。这导致了误导性的时间戳记录。

最终我能够在更新中使用聚合获得解决方案,但是,有些东西并没有像我预期的那样工作。我只能假设这是一个错误,除非我的理解是错误的。请看代码sn-ps。

更正:以下两种方法均无效(但是,如果我用值硬替换字段路径,例如将“$firstName”更改为“Steve”有效,它们确实有效)


    $set: 
        lastModified: 
            $switch: 
                branches: [
                    
                        case: 
                            $ne: ['$firstName', firstName],
                        ,
                        then: new Date(),
                    ,
                    
                        case: 
                            $ne: ['$lastName', lastName],
                        ,
                        then: new Date(),
                    ,
                ],
                default: '$lastModified',
            ,
        ,
    ,
,

    $set: 
        lastModified: 
            $switch: 
                branches: [
                    
                        case: 
                            $not:  $eq: ['$firstName', firstName] 
                        ,
                        then: new Date(),
                    ,
                    
                        case: 
                            $not:  $eq: ['$lastName', lastName] 
                        ,
                        then: new Date(),
                    ,
                ],
                default: '$lastModified',
            ,
        ,
    ,
,

如果有人能对此提供一些说明,我将不胜感激。

编辑:添加了更多细节

// firstName = 'Steve', lastName = 'Jobs'
// In db, $firstName field = 'John', $lastName field = 'Doe'
// the intention is to compare user input with db fields and 
// detect changes using the switch statement
const  firstName, lastName  = req.body

db.collection.updateOne(
     _id ,
    [
        
            $set: 
                firstName,
                lastName,
            ,
        ,
        
            $set: 
                lastModified: 
                    $switch: 
                        branches: [
                            
                                case: 
                                    $not: 
                                        $eq: ['$firstName', firstName],
                                    ,
                                ,
                                then: new Date(),
                            ,
                            
                                case: 
                                    $not: 
                                        $eq: ['$lastName', lastName],
                                    ,
                                ,
                                then: new Date(),
                            ,
                        ],
                        default: '$lastModified',
                    ,
                ,
            ,
        ,
    ],
     ignoreUndefined: true ,
)

我希望 db 文档改变


    firstName: 'John',
    lastName: 'Doe',
    lastModified: ~previous timestamp~


    firstName: 'Steve',
    lastName: 'Jobs',
    lastModified: ~new timestamp~

不管怎样


    firstName: 'Steve',
    lastName: 'Jobs',
    lastModified: ~previous timestamp~

仅当两个变量之一被硬编码时才有效,即

case: 
    $not: 
        $eq: ['$firstName', firstName],
    ,
    then: 'DOES NOT enter here'
,
case: 
    $not: 
        $eq: ['John', firstName],
    ,
    then: 'DOES enter here'
,
case: 
    $not: 
        $eq: ['$firstName', 'Steve'],
    ,
    then: 'DOES enter here'
,

目前,我决定(暂时)使用两个查询来更新 lastModified 字段,但我一点也不喜欢这种方法。第二个查询是:

if (modifiedCount > 0 || upsertedCount > 0) 
    dbCollection
            .updateOne(filter, update)
            .catch((err) => console.error(err))

【问题讨论】:

您能否提供一个示例文档和一个您想要实现的输出示例?我尝试了您的代码 here 和 here,它们的行为符合我的预期。 我添加了更多细节。如果有帮助,请告诉我。 【参考方案1】:

您的更新语句不起作用的原因是您有两个连续的$set 阶段。让我们来看看更新此文档时会发生什么:


    firstName: 'John',
    lastName: 'Doe',
    lastModified: ~previous timestamp~

第一个$set 阶段将更新firstNamelastName 字段,生成如下文档:


    firstName: 'Steve',
    lastName: 'Jobs',
    lastModified: ~previous timestamp~

这个生成的文档然后被传递到第二个$set 阶段。在$switch 内部,您正在比较$firstNamefirstName$lastNamelastName 的值。但是因为您已经在上一阶段更新了这些值,所以它们将始终保持不变。

您可以将两个阶段合二为一,这样$switch 案例中的$firstName$lastName 变量将引用它们的原始值:

db.collection.updateOne(
     _id ,
    [
        
            $set: 
                firstName,
                lastName,
                lastModified: 
                    $switch: 
                        branches: [
                            
                                case:  $ne: [ "$firstName", firstName ] ,
                                then: new Date()
                            ,
                            
                                case:  $ne: [ "$lastName", lastName ] ,
                                then: new Date(),
                            
                        ],
                        default: "$lastModified"
                    
                
            
        
    ],
     ignoreUndefined: true ,
)

【讨论】:

啊,这很有道理。它现在按预期工作,谢谢一百万!!!

以上是关于本机 MongoDB:为啥我的 switch 语句不能使用字段名称,而只能使用硬编码值?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这两个语句是等价的

为啥 switch 语句没有大括号?

switch语句括号中的东西为啥一定得是整型的?

为啥 Switch 需要语句但接受表达式

为啥 switch 语句上有奇怪的缩进?

这个PHP流程判断switch语句哪里出错了?为啥不执行default后面的语句