【问题标题】:mongoose @set and $unset conditional猫鼬 @set 和 $unset 条件
【发布时间】:2020-04-15 20:44:00
【问题描述】:

在我的项目中,我想在文档中允许可选字段,但我不想保存任何空值,即我想删除任何带有空值的字段。

这些值可以在运行时更改。

我发现如果用户没有发送数据来更新字段,我如何使字段为空(用户发送空值的所有字段都应该被删除)。

如果用户以我想删除的形式将名字/姓氏作为空字符串发送。

await Employee.findOneAndUpdate({ _id: employee._id },
     {$set: {firstName: null, lastName: null, ...req.body.newEmployee}}, { new: true, upsert: false });

我尝试添加一个 $unset 选项,但出现错误

MongoError: Updating the path 'firstName' would create a conflict at 'firstName'

我考虑在更新后删除它(作为第二个命令),但我找不到告诉/获取员工的所有空字段的方法,而且我无法获得要检查的固定值,因为那里null/not null 值有很多组合,特别是如果将来会有更多字段。 即我无法判断(FN:null,LN:null 还是 FN:“johny”,LN:null 等)

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    更新:如果您需要保留现有文档中的某些字段,请尝试此操作,使用此新代码,只有请求中的字段将被更新或删除,不会改变文档中的其他现有字段:

    你的 node.js 代码:

    let removeObj = {}
    Object.entries(req.body).forEach(([key, val]) => {
        if (!val) { delete req[body][key]; removeObj[key] = '' };
    })
    
    let bulkArr = []
    if (req.body) bulkArr.push({
        updateOne: {
            "filter": { "_id": ObjectId("5e02da86400289966e8ffa4f") },
            "update": { $set: req.body }
        }
    })
    if (Object.entries(removeObj).length > 0 && removeObj.constructor === Object) bulkArr.push({
        updateOne: {
            "filter": { "_id": ObjectId("5e02da86400289966e8ffa4f") },
            "update": { $unset: removeObj }
        }
    })
    
    
    // For mongoDB4.2 removeObj has to be an array of strings(field names)
    let removeObj = []
    Object.entries(req.body).forEach(([key, val]) => {
        if (!val) { delete req[body][key]; removeObj.push(key) };
    })
    // After this, Similar to above you need to write code to exclude empty removeObj for 4.2 as well.
    

    Query :: On mongoDB version >= 3.2 to .bulkWrite():

    db.yourCollectionName.bulkWrite(bulkArr) 
    

    查询 :: 从 mongoDB 版本 4.2 .updateOne accepts aggregation pipeline :

    db.yourCollectionName.updateOne(
        { "_id": ObjectId("5e02da86400289966e8ffa4f") },
        [
            {
                $set: req.body
            },
            { $unset: removeObj }
        ]
    )
    

    旧答案:如果您想替换整个文档,您需要尝试.findOneAndReplace()

    db.yourCollectionName.findOneAndReplace({_id: ObjectId("5e02da86400289966e8ffa4f")},inputObj, {returnNewDocument:true})
    

    您的收藏:

    {
        "_id" : ObjectId("5e02da86400289966e8ffa4f"),
        "firstName" : "noName",
        "lastName": 'noName',
        "value" : 1.0,
        "empDept": 'general',
        "password":'something'
    }
    

    你的请求对象是这样的:

    req.body = {
        firstName: 'firstName',
        lastName: null,
        value : 1.0,
        empDept: ''
    }
    

    您的 node.js 代码(删除所有虚假值(“”、0、false、null、未定义)):

    let inputObj = Object.entries(req.body).reduce((a,[k,v]) => (v ? {...a, [k]:v} : a), {})
    

    您的术后收藏:

    {
        "_id" : ObjectId("5e02da86400289966e8ffa4f"),
        "firstName" : "firstName",
        "value" : 1.0,
    }
    

    您根据更新后的答案收藏:

    {
        "_id" : ObjectId("5e02da86400289966e8ffa4f"),
        "firstName" : "firstName",
        "value" : 1.0,
        "password":'something'
    }
    

    【讨论】:

    • 嗨,谢谢,太好了!你知道是否还可以保留一些字段?我有一个密码字段,我只在注册和登录期间与之交互,我想保留它
    • @guy : 你的 mongoDB 版本是多少?
    • mongoDb 4.0.13,猫鼬 5.7.14
    猜你喜欢
    • 2021-10-07
    • 2021-04-07
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2021-06-29
    • 2019-03-15
    • 2018-05-16
    • 2021-08-27
    相关资源
    最近更新 更多