Javascript 如何使用Sails.js&;更新MongoDB子文档中的特定密钥;水线?

Javascript 如何使用Sails.js&;更新MongoDB子文档中的特定密钥;水线?,javascript,node.js,mongodb,sails.js,waterline,Javascript,Node.js,Mongodb,Sails.js,Waterline,我在尝试使用Sails.js和Waterline ORM更新MongoDB子文档中的单个键时遇到了一个问题。这就是我的person.js模型的外观: module.exports = { attributes: { name: { type: 'string', required: true }, favorites: { type: 'json', defaultsTo: {

我在尝试使用Sails.js和Waterline ORM更新MongoDB子文档中的单个键时遇到了一个问题。这就是我的
person.js
模型的外观:

module.exports = {
    attributes: {
        name: { type: 'string', required: true },
        favorites: {
            type: 'json',
            defaultsTo: {
                color: null,
                place: null,
                season: null
            }
        }
    }
}
现在,假设我想从我的控制器中更新特定人员的姓名和最喜爱的季节,我正在这样做:

Person.update({ id: '1' }, {
    name: 'Dan',
    favorites: {
        season: 'Summer'
    }
}).exec(function(error, updatedPerson) {

    console.log(updatedPerson);
});

当我运行此操作时,
favorites
对象将被完全替换,只保留我更新的一个键(季节键),而不是保留另外两个键(颜色和位置),同时只更新我想要的一个键。我错过了什么?如何让它只更新我指定的键?

只需使用以下命令更改查询:

Person.update({ id: '1' },{ name: 'Dan',favorites: { $set: {season: Summer'}}}})
您可以在模型上使用直接访问mongo驱动程序的方法,然后使用操作符独立更新字段。但是,您需要首先将对象转换为具有点符号的一级文档,如

{
    "name": "Dan",
    "favorites.season": "Summer"
}
因此,您可以将其用作:

var criteria = { "id": "1" },
    update = { "$set": { "name": "Dan", "favorites.season": "Summer" } },
    options = { "new": true };

// Grab an instance of the mongo-driver
Person.native(function(err, collection) {        
    if (err) return res.serverError(err);

    // Execute any query that works with the mongo js driver
    collection.findAndModify(
        criteria, 
        null,
        update,
        options,
        function (err, updatedPerson) {
            console.log(updatedPerson);
        }
    );
});
要转换需要更新的原始对象,请使用以下函数

var convertNestedObjectToDotNotation = function(obj){
    var res = {};
    (function recurse(obj, current) {
        for(var key in obj) {
            var value = obj[key];
            var newKey = (current ? current + "." + key : key);  // joined key with dot
            if  (value && typeof value === "object") {
                recurse(value, newKey);  // it's a nested object, so do it again
            } else {
                res[newKey] = value;  // it's not an object, so set the property
            }
        }
    })(obj);

    return res;
}
然后您可以将其作为更新调用

var criteria = { "id": "1" },
    update = { "$set": convertNestedObjectToDotNotation(params) },
    options = { "new": true };
查看下面的演示

var示例={
“姓名”:“丹”,
“收藏夹”:{
“季节”:“冬天”
}
};
var convertedObjectToDotNotation=函数(obj){
var res={};
(函数递归(obj,当前){
for(obj中的var键){
var值=obj[键];
var newKey=(当前?当前+“+键:键);//用点连接键
if(值和类型值==“对象”){
recurse(value,newKey);//这是一个嵌套对象,所以请再次执行
}否则{
res[newKey]=value;//它不是对象,所以设置属性
}
}
})(obj);
返回res;
}
var update={“$set”:convertedObjectToDotNotation(示例)};
pre.innerHTML=“update=“+JSON.stringify(update,null,4)

问题是,需要更新的参数是由使用我们的API的客户端应用程序发送的。我们不能强迫API的用户使用$set等来发送它。他们会向我们发送一个原始JSON对象。还可以吗?检查所有要更新的嵌套对象,然后在该对象上使用$set。效果很好!尽管我应该补充一点,我必须引用它,因为本机查询
{“id”:1}
不能自动工作,因为MongoDB使用ObjectId作为id。