admin管理员组

文章数量:1389754

I have a simple user model:

{
  _id: "59d72070d9d03b28934b972b"
  firstName: "first"
  lastName: "last"
  email: "[email protected]"
  subscriptions: {
    newsletter: true,
    blog: true
  }
}

I'm trying to do partial updates on the subscriptions object. I'm passing the id of the user and a payload object that can have either one or both properties of the object. Let's say I only want to update newsletter and set it to false. I'll send:

{ id: "59d72070d9d03b28934b972b", payload: { newsletter: false } }

And then:

const user = await User.findByIdAndUpdate(
  args.id,
  { $set: { subscriptions: args.payload } },
  { upsert: true, new: true }
);

This will return:

subscriptions: {
  newsletter: false
}

Is there a way to only modify the newsletter property when I only pass newsletter in the payload object without deleting the other properties? I know I only have two properties in this example, but in time, the object will keep expanding.

I have a simple user model:

{
  _id: "59d72070d9d03b28934b972b"
  firstName: "first"
  lastName: "last"
  email: "[email protected]"
  subscriptions: {
    newsletter: true,
    blog: true
  }
}

I'm trying to do partial updates on the subscriptions object. I'm passing the id of the user and a payload object that can have either one or both properties of the object. Let's say I only want to update newsletter and set it to false. I'll send:

{ id: "59d72070d9d03b28934b972b", payload: { newsletter: false } }

And then:

const user = await User.findByIdAndUpdate(
  args.id,
  { $set: { subscriptions: args.payload } },
  { upsert: true, new: true }
);

This will return:

subscriptions: {
  newsletter: false
}

Is there a way to only modify the newsletter property when I only pass newsletter in the payload object without deleting the other properties? I know I only have two properties in this example, but in time, the object will keep expanding.

Share Improve this question asked Oct 7, 2017 at 9:51 NorbertNorbert 2,7718 gold badges57 silver badges113 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

To update only the nested field, use { "subscriptions.newsletter": false } :

const user = (await User.findByIdAndUpdate(
    args.id, {
        $set: {
            "subscriptions.newsletter": args.payload
        }
    }, {
        new: true
    }
));

If your input can have missing fields, you can build a dynamic query in $set with only the fields you have specified in your input :

async function save(id, query) {
    const user = (await User.findByIdAndUpdate(
        id, {
            $set: query
        }, {
            new: true
        }
    ));
    console.log(user);
}

var id = mongoose.Types.ObjectId("59d91f1a06ecf429c8aae221");
var input = {
    newsletter: false,
    blog: false
};

var query = {};
for (var key in input) {
    query["subscriptions." + key] = input[key];
}

save(id, query);

I ended up doing the following:

const user = await User.findById(args.id);

// merge subscriptions
user.subscriptions = Object.assign({}, user.subscriptions, args.payload);

return user.save();

To partial update parent doc and/or subDoc, formulate payload as:

const args = { id: "59d72070d9d03b28934b972b", payload: { firstName: "John", subscriptions.newsletter: false } }

await User.findByIdAndUpdate(args.id, args.payload);

本文标签: javascriptMongoose partial update of an objectStack Overflow