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

Native MongoDB: Why is my switch statement not working with field names but only hard coded values?

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

最终我能够在更新中使用聚合获得一个解决方案,但是,有些东西并不像我预期的那样有效。除非我的理解有误,否则我只能假设这是一个错误。请查看代码片段。

更正:以下均无效(但是,如果我硬用值替换字段路径,它们确实有效,例如将“$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 },
)

我希望数据库文件从

{
    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))
}

您的更新语句不起作用的原因是您有两个 $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 },
)