如何做到 findByIdAndUpdate 仅更新不为空的字段?
发布于 10天前 作者 rankun203 230 次浏览 来自 问答

Happy sunshine.

Screen Shot 2015-08-02 at 11.58.56 AM.png

如果要根据传入的参数来更新目标文档的部分数据要怎么做呢?

例如我传入了 creator, 就只更新 creator. 而不是将 update 对象内容全部更新. 同理, 传入 name 就只更新 name.

现在 MongoDB 的 $set 似乎还是得一次性指定所有要更新的参数, 而不能根据传入的值是否为空来确定是否要更新.

类似于 MyBatis 里面的 UpdateSchemaSelective()

谢谢~

如果我这样的想法本身有问题, 请指正, 谢谢~

5 回复

封装一下,根据传入的更新对象动态生成带$set的update对象

@ravenwang 不用封装用个最简单的方法 使用underscorejs 中的extend方法

extend_.extend(destination, *sources)

复制source对象中的所有属性覆盖到destination对象上,并且返回 destination 对象. 复制是按顺序的, 所以后面的对象属性会把前面的对象属性覆盖掉(如果有重复).

_.extend({name: 'moe'}, {age: 50});
=> {name: 'moe', age: 50}

取出来的数据用 extend 方法把新更新的数据合并再使用 findByIdAndUpdate 更新。

@jaywcjlove 好办法,不过要考虑是用extend还是merge

@ravenwang underscorejs 方法很多哦,提供接口也很多。

@ravenwang @jaywcjlove 谢谢 汗, 为了搞定这个问题, 我弄了一个方法来根据传入的参数创建对象, 我再看看你们的办法.

/**
 * Convert a series of arguments to an object,
 * arguments length should be a even number.
 * @returns {{}} the generated Object
 */
exports.constructObj = function () {
    var obj = {};
// TODO throw???
    if (arguments.length % 2 != 0) {
        throw new Error('Arguments length should be an even number: ' + arguments);
    }

    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i + 1]) {
            obj[arguments[i]] = arguments[i + 1];
        }
        i++;
    }
    return obj;
};

调用方法:

helper.constructObj(
        'email', req.body.email,
        'password', req.body.password,
        'avatar', req.body.avatar,
        'nickname', req.body.nickname,
        'sex', req.body.sex
)
回到顶部