How do I update a specific key inside a MongoDB sub-document using Sails.js & Waterline?

邮差的信 提交于 2019-12-11 08:39:59

问题


I face an issue when trying to update a single key inside a MongoDB sub-document using Sails.js and the Waterline ORM. This is what my person.js model looks like:

module.exports = {
    attributes: {
        name: { type: 'string', required: true },
        favorites: {
            type: 'json',
            defaultsTo: {
                color: null,
                place: null,
                season: null
            }
        }
    }
}

Now, let's say I want to update a specific person's name and favorite season from my controller, I am doing this:

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

    console.log(updatedPerson);
});

When I run this, the favorites object gets entirely replaced to just have the one key that I updated (the season key) instead of retaining the other two keys (color and place) while updating just the one I want. What am I missing? How do I get it to only update the keys that I specify?


回答1:


You can use the .native() method on your model that has direct access to the mongo driver and then the $set operator to update the fields independently. However, you need to first convert the object to a one-level document which has the dot notation like

{
    "name": "Dan",
    "favorites.season": "Summer"
}

so that you can use that as:

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

To convert the raw object that needs to be updated, use the following function

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;
}

which you can then call in your update as

var criteria = { "id": "1" },
    update = { "$set": convertNestedObjectToDotNotation(params) },
    options = { "new": true };

Check the demo below.

var example = {
	"name" : "Dan",
	"favorites" : {
		"season" : "winter"
	}
};

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 update = { "$set": convertNestedObjectToDotNotation(example) };

pre.innerHTML = "update =  " + JSON.stringify(update, null, 4);
<pre id="pre"></pre>



回答2:


Just alter your query with:

Person.update({ id: '1' },{ name: 'Dan',favorites: { $set: {season: Summer'}}}})


来源:https://stackoverflow.com/questions/40741373/how-do-i-update-a-specific-key-inside-a-mongodb-sub-document-using-sails-js-wa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!