问题
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